mathhook_core/functions/elementary/trigonometric/
trig_inverse.rs

1//! Inverse Trigonometric Functions (arcsin, arccos, arctan, arcsec, arccsc, arccot)
2//!
3//! Complete mathematical intelligence for inverse trigonometric functions
4//! with derivatives, domain restrictions, and special values.
5
6use crate::core::Expression;
7use crate::core::Symbol;
8use crate::functions::properties::*;
9use std::collections::HashMap;
10use std::sync::Arc;
11
12/// Inverse Trigonometric Function Intelligence
13///
14/// Dedicated intelligence for arcsin, arccos, arctan, arcsec, arccsc, arccot
15pub struct InverseTrigIntelligence {
16    properties: HashMap<String, FunctionProperties>,
17}
18
19impl Default for InverseTrigIntelligence {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl InverseTrigIntelligence {
26    /// Create new inverse trigonometric intelligence system
27    pub fn new() -> Self {
28        let mut intelligence = Self {
29            properties: HashMap::with_capacity(6),
30        };
31
32        intelligence.initialize_inverse_trig();
33
34        intelligence
35    }
36
37    /// Get all inverse trigonometric function properties
38    pub fn get_properties(&self) -> HashMap<String, FunctionProperties> {
39        self.properties.clone()
40    }
41
42    /// Check if function is inverse trigonometric
43    pub fn has_function(&self, name: &str) -> bool {
44        self.properties.contains_key(name)
45    }
46
47    /// Initialize inverse trigonometric functions
48    fn initialize_inverse_trig(&mut self) {
49        self.properties.insert(
50            "arcsin".to_owned(),
51            FunctionProperties::Elementary(Box::new(ElementaryProperties {
52                derivative_rule: Some(DerivativeRule {
53                    rule_type: DerivativeRuleType::Custom {
54                        builder: Arc::new(|arg: &Expression| {
55                            Expression::pow(
56                                Expression::function(
57                                    "sqrt",
58                                    vec![Expression::add(vec![
59                                        Expression::integer(1),
60                                        Expression::mul(vec![
61                                            Expression::integer(-1),
62                                            Expression::pow(arg.clone(), Expression::integer(2)),
63                                        ]),
64                                    ])],
65                                ),
66                                Expression::integer(-1),
67                            )
68                        }),
69                    },
70                    result_template: "1/√(1-x²)".to_owned(),
71                }),
72                antiderivative_rule: Some(AntiderivativeRule {
73                    rule_type: AntiderivativeRuleType::Custom {
74                        builder: Arc::new(|var: Symbol| {
75                            Expression::add(vec![
76                                Expression::mul(vec![
77                                    Expression::symbol(var.clone()),
78                                    Expression::function(
79                                        "arcsin",
80                                        vec![Expression::symbol(var.clone())],
81                                    ),
82                                ]),
83                                Expression::function(
84                                    "sqrt",
85                                    vec![Expression::add(vec![
86                                        Expression::integer(1),
87                                        Expression::mul(vec![
88                                            Expression::integer(-1),
89                                            Expression::pow(
90                                                Expression::symbol(var),
91                                                Expression::integer(2),
92                                            ),
93                                        ]),
94                                    ])],
95                                ),
96                            ])
97                        }),
98                    },
99                    result_template: "∫arcsin(x)dx = x·arcsin(x) + √(1-x²) + C".to_owned(),
100                    constant_handling: ConstantOfIntegration::AddConstant,
101                }),
102                special_values: vec![],
103                identities: Box::new(vec![]),
104                domain_range: Box::new(DomainRangeData {
105                    domain: Domain::Interval(Expression::integer(-1), Expression::integer(1)),
106                    range: Range::Bounded(
107                        Expression::mul(vec![Expression::rational(-1, 2), Expression::pi()]),
108                        Expression::mul(vec![Expression::rational(1, 2), Expression::pi()]),
109                    ),
110                    singularities: vec![],
111                }),
112                periodicity: None,
113                wolfram_name: Some("ArcSin"),
114            })),
115        );
116
117        self.properties.insert(
118            "arccos".to_owned(),
119            FunctionProperties::Elementary(Box::new(ElementaryProperties {
120                derivative_rule: Some(DerivativeRule {
121                    rule_type: DerivativeRuleType::Custom {
122                        builder: Arc::new(|arg: &Expression| {
123                            Expression::mul(vec![
124                                Expression::integer(-1),
125                                Expression::pow(
126                                    Expression::function(
127                                        "sqrt",
128                                        vec![Expression::add(vec![
129                                            Expression::integer(1),
130                                            Expression::mul(vec![
131                                                Expression::integer(-1),
132                                                Expression::pow(
133                                                    arg.clone(),
134                                                    Expression::integer(2),
135                                                ),
136                                            ]),
137                                        ])],
138                                    ),
139                                    Expression::integer(-1),
140                                ),
141                            ])
142                        }),
143                    },
144                    result_template: "-1/√(1-x²)".to_owned(),
145                }),
146                antiderivative_rule: Some(AntiderivativeRule {
147                    rule_type: AntiderivativeRuleType::Custom {
148                        builder: Arc::new(|var: Symbol| {
149                            Expression::add(vec![
150                                Expression::mul(vec![
151                                    Expression::symbol(var.clone()),
152                                    Expression::function(
153                                        "arccos",
154                                        vec![Expression::symbol(var.clone())],
155                                    ),
156                                ]),
157                                Expression::mul(vec![
158                                    Expression::integer(-1),
159                                    Expression::function(
160                                        "sqrt",
161                                        vec![Expression::add(vec![
162                                            Expression::integer(1),
163                                            Expression::mul(vec![
164                                                Expression::integer(-1),
165                                                Expression::pow(
166                                                    Expression::symbol(var),
167                                                    Expression::integer(2),
168                                                ),
169                                            ]),
170                                        ])],
171                                    ),
172                                ]),
173                            ])
174                        }),
175                    },
176                    result_template: "∫arccos(x)dx = x·arccos(x) - √(1-x²) + C".to_owned(),
177                    constant_handling: ConstantOfIntegration::AddConstant,
178                }),
179                special_values: vec![],
180                identities: Box::new(vec![]),
181                domain_range: Box::new(DomainRangeData {
182                    domain: Domain::Interval(Expression::integer(-1), Expression::integer(1)),
183                    range: Range::Bounded(Expression::integer(0), Expression::pi()),
184                    singularities: vec![],
185                }),
186                periodicity: None,
187                wolfram_name: Some("ArcCos"),
188            })),
189        );
190
191        self.properties.insert(
192            "arctan".to_owned(),
193            FunctionProperties::Elementary(Box::new(ElementaryProperties {
194                derivative_rule: Some(DerivativeRule {
195                    rule_type: DerivativeRuleType::Custom {
196                        builder: Arc::new(|arg: &Expression| {
197                            Expression::pow(
198                                Expression::add(vec![
199                                    Expression::integer(1),
200                                    Expression::pow(arg.clone(), Expression::integer(2)),
201                                ]),
202                                Expression::integer(-1),
203                            )
204                        }),
205                    },
206                    result_template: "1/(1+x²)".to_owned(),
207                }),
208                antiderivative_rule: Some(AntiderivativeRule {
209                    rule_type: AntiderivativeRuleType::Custom {
210                        builder: Arc::new(|var: Symbol| {
211                            Expression::add(vec![
212                                Expression::mul(vec![
213                                    Expression::symbol(var.clone()),
214                                    Expression::function(
215                                        "arctan",
216                                        vec![Expression::symbol(var.clone())],
217                                    ),
218                                ]),
219                                Expression::mul(vec![
220                                    Expression::rational(-1, 2),
221                                    Expression::function(
222                                        "ln",
223                                        vec![Expression::add(vec![
224                                            Expression::integer(1),
225                                            Expression::pow(
226                                                Expression::symbol(var),
227                                                Expression::integer(2),
228                                            ),
229                                        ])],
230                                    ),
231                                ]),
232                            ])
233                        }),
234                    },
235                    result_template: "∫arctan(x)dx = x·arctan(x) - ½ln(1+x²) + C".to_owned(),
236                    constant_handling: ConstantOfIntegration::AddConstant,
237                }),
238                special_values: vec![],
239                identities: Box::new(vec![]),
240                domain_range: Box::new(DomainRangeData {
241                    domain: Domain::Real,
242                    range: Range::Bounded(
243                        Expression::mul(vec![Expression::rational(-1, 2), Expression::pi()]),
244                        Expression::mul(vec![Expression::rational(1, 2), Expression::pi()]),
245                    ),
246                    singularities: vec![],
247                }),
248                periodicity: None,
249                wolfram_name: Some("ArcTan"),
250            })),
251        );
252
253        self.properties.insert(
254            "arcsec".to_owned(),
255            FunctionProperties::Elementary(Box::new(ElementaryProperties {
256                derivative_rule: Some(DerivativeRule {
257                    rule_type: DerivativeRuleType::Custom {
258                        builder: Arc::new(|arg: &Expression| {
259                            let abs_arg = Expression::function("abs", vec![arg.clone()]);
260                            let sqrt_term = Expression::function(
261                                "sqrt",
262                                vec![Expression::add(vec![
263                                    Expression::pow(arg.clone(), Expression::integer(2)),
264                                    Expression::integer(-1),
265                                ])],
266                            );
267                            Expression::pow(
268                                Expression::mul(vec![abs_arg, sqrt_term]),
269                                Expression::integer(-1),
270                            )
271                        }),
272                    },
273                    result_template: "1/(|x|·√(x²-1))".to_owned(),
274                }),
275                antiderivative_rule: None,
276                special_values: vec![],
277                identities: Box::new(vec![]),
278                domain_range: Box::new(DomainRangeData {
279                    domain: Domain::Real,
280                    range: Range::Bounded(Expression::integer(0), Expression::pi()),
281                    singularities: vec![],
282                }),
283                periodicity: None,
284                wolfram_name: Some("ArcSec"),
285            })),
286        );
287
288        self.properties.insert(
289            "arccsc".to_owned(),
290            FunctionProperties::Elementary(Box::new(ElementaryProperties {
291                derivative_rule: Some(DerivativeRule {
292                    rule_type: DerivativeRuleType::Custom {
293                        builder: Arc::new(|arg: &Expression| {
294                            let abs_arg = Expression::function("abs", vec![arg.clone()]);
295                            let sqrt_term = Expression::function(
296                                "sqrt",
297                                vec![Expression::add(vec![
298                                    Expression::pow(arg.clone(), Expression::integer(2)),
299                                    Expression::integer(-1),
300                                ])],
301                            );
302                            Expression::mul(vec![
303                                Expression::integer(-1),
304                                Expression::pow(
305                                    Expression::mul(vec![abs_arg, sqrt_term]),
306                                    Expression::integer(-1),
307                                ),
308                            ])
309                        }),
310                    },
311                    result_template: "-1/(|x|·√(x²-1))".to_owned(),
312                }),
313                antiderivative_rule: None,
314                special_values: vec![],
315                identities: Box::new(vec![]),
316                domain_range: Box::new(DomainRangeData {
317                    domain: Domain::Real,
318                    range: Range::Bounded(
319                        Expression::mul(vec![Expression::rational(-1, 2), Expression::pi()]),
320                        Expression::mul(vec![Expression::rational(1, 2), Expression::pi()]),
321                    ),
322                    singularities: vec![],
323                }),
324                periodicity: None,
325                wolfram_name: Some("ArcCsc"),
326            })),
327        );
328
329        self.properties.insert(
330            "arccot".to_owned(),
331            FunctionProperties::Elementary(Box::new(ElementaryProperties {
332                derivative_rule: Some(DerivativeRule {
333                    rule_type: DerivativeRuleType::Custom {
334                        builder: Arc::new(|arg: &Expression| {
335                            Expression::mul(vec![
336                                Expression::integer(-1),
337                                Expression::pow(
338                                    Expression::add(vec![
339                                        Expression::integer(1),
340                                        Expression::pow(arg.clone(), Expression::integer(2)),
341                                    ]),
342                                    Expression::integer(-1),
343                                ),
344                            ])
345                        }),
346                    },
347                    result_template: "-1/(1+x²)".to_owned(),
348                }),
349                antiderivative_rule: None,
350                special_values: vec![],
351                identities: Box::new(vec![]),
352                domain_range: Box::new(DomainRangeData {
353                    domain: Domain::Real,
354                    range: Range::Bounded(Expression::integer(0), Expression::pi()),
355                    singularities: vec![],
356                }),
357                periodicity: None,
358                wolfram_name: Some("ArcCot"),
359            })),
360        );
361    }
362}
363
364#[cfg(test)]
365mod tests {
366    use super::*;
367
368    #[test]
369    fn test_inverse_trig_intelligence() {
370        let inv_trig = InverseTrigIntelligence::new();
371
372        assert!(inv_trig.has_function("arcsin"));
373        assert!(inv_trig.has_function("arccos"));
374        assert!(inv_trig.has_function("arctan"));
375        assert!(inv_trig.has_function("arcsec"));
376        assert!(inv_trig.has_function("arccsc"));
377        assert!(inv_trig.has_function("arccot"));
378        assert!(!inv_trig.has_function("sin"));
379
380        let properties = inv_trig.get_properties();
381        assert_eq!(properties.len(), 6);
382    }
383
384    #[test]
385    fn test_inverse_trig_derivative_rules() {
386        let inv_trig = InverseTrigIntelligence::new();
387        let properties = inv_trig.get_properties();
388
389        if let Some(FunctionProperties::Elementary(arcsin_props)) = properties.get("arcsin") {
390            assert!(arcsin_props.derivative_rule.is_some());
391            let deriv = arcsin_props.derivative_rule.as_ref().unwrap();
392            assert!(matches!(deriv.rule_type, DerivativeRuleType::Custom { .. }));
393        } else {
394            panic!("arcsin properties not found");
395        }
396
397        if let Some(FunctionProperties::Elementary(arctan_props)) = properties.get("arctan") {
398            assert!(arctan_props.derivative_rule.is_some());
399            let deriv = arctan_props.derivative_rule.as_ref().unwrap();
400            assert!(matches!(deriv.rule_type, DerivativeRuleType::Custom { .. }));
401        } else {
402            panic!("arctan properties not found");
403        }
404    }
405}