1use crate::core::Expression;
7use crate::core::Symbol;
8use crate::functions::properties::*;
9use std::collections::HashMap;
10use std::sync::Arc;
11
12pub 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 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 pub fn get_properties(&self) -> HashMap<String, FunctionProperties> {
39 self.properties.clone()
40 }
41
42 pub fn has_function(&self, name: &str) -> bool {
44 self.properties.contains_key(name)
45 }
46
47 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}