1use crate::core::{Expression, Symbol};
7use crate::functions::properties::*;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11pub struct HyperbolicIntelligence {
16 properties: HashMap<String, FunctionProperties>,
18}
19
20impl Default for HyperbolicIntelligence {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl HyperbolicIntelligence {
27 pub fn new() -> Self {
29 let mut intelligence = Self {
30 properties: HashMap::with_capacity(12),
31 };
32
33 intelligence.initialize_sinh_cosh();
34 intelligence.initialize_tanh();
35 intelligence.initialize_extended();
36 intelligence.initialize_inverse();
37
38 intelligence
39 }
40
41 pub fn get_properties(&self) -> HashMap<String, FunctionProperties> {
43 self.properties.clone()
44 }
45
46 pub fn has_function(&self, name: &str) -> bool {
48 self.properties.contains_key(name)
49 }
50
51 fn initialize_sinh_cosh(&mut self) {
53 self.properties.insert(
54 "sinh".to_owned(),
55 FunctionProperties::Elementary(Box::new(ElementaryProperties {
56 derivative_rule: Some(DerivativeRule {
57 rule_type: DerivativeRuleType::SimpleFunctionSubstitution("cosh".to_owned()),
58 result_template: "cosh(x)".to_owned(),
59 }),
60 antiderivative_rule: Some(AntiderivativeRule {
61 rule_type: AntiderivativeRuleType::Simple {
62 antiderivative_fn: "cosh".to_owned(),
63 coefficient: Expression::integer(1),
64 },
65 result_template: "∫sinh(x)dx = cosh(x) + C".to_owned(),
66 constant_handling: ConstantOfIntegration::AddConstant,
67 }),
68 special_values: vec![SpecialValue {
69 input: "0".to_owned(),
70 output: Expression::integer(0),
71 latex_explanation: "\\sinh(0) = 0".to_owned(),
72 }],
73 identities: Box::new(vec![MathIdentity {
74 name: "Hyperbolic Identity".to_owned(),
75 lhs: Expression::function(
76 "cosh_squared_minus_sinh_squared",
77 vec![Expression::symbol("x")],
78 ),
79 rhs: Expression::integer(1),
80 conditions: vec!["x ∈ ℝ".to_owned()],
81 }]),
82 domain_range: Box::new(DomainRangeData {
83 domain: Domain::Real,
84 range: Range::Real,
85 singularities: vec![],
86 }),
87 periodicity: None,
88 wolfram_name: None,
89 })),
90 );
91
92 self.properties.insert(
93 "cosh".to_owned(),
94 FunctionProperties::Elementary(Box::new(ElementaryProperties {
95 derivative_rule: Some(DerivativeRule {
96 rule_type: DerivativeRuleType::SimpleFunctionSubstitution("sinh".to_owned()),
97 result_template: "sinh(x)".to_owned(),
98 }),
99 antiderivative_rule: Some(AntiderivativeRule {
100 rule_type: AntiderivativeRuleType::Simple {
101 antiderivative_fn: "sinh".to_owned(),
102 coefficient: Expression::integer(1),
103 },
104 result_template: "∫cosh(x)dx = sinh(x) + C".to_owned(),
105 constant_handling: ConstantOfIntegration::AddConstant,
106 }),
107 special_values: vec![SpecialValue {
108 input: "0".to_owned(),
109 output: Expression::integer(1),
110 latex_explanation: "\\cosh(0) = 1".to_owned(),
111 }],
112 identities: Box::new(vec![MathIdentity {
113 name: "Hyperbolic Identity".to_owned(),
114 lhs: Expression::function(
115 "cosh_squared_minus_sinh_squared",
116 vec![Expression::symbol("x")],
117 ),
118 rhs: Expression::integer(1),
119 conditions: vec!["x ∈ ℝ".to_owned()],
120 }]),
121 domain_range: Box::new(DomainRangeData {
122 domain: Domain::Real,
123 range: Range::Unbounded,
124 singularities: vec![],
125 }),
126 periodicity: None,
127 wolfram_name: None,
128 })),
129 );
130 }
131
132 fn initialize_tanh(&mut self) {
134 self.properties.insert(
135 "tanh".to_owned(),
136 FunctionProperties::Elementary(Box::new(ElementaryProperties {
137 derivative_rule: Some(DerivativeRule {
138 rule_type: DerivativeRuleType::Custom {
139 builder: Arc::new(|arg: &Expression| {
140 let tanh_arg = Expression::function("tanh", vec![arg.clone()]);
141 let tanh_squared = Expression::pow(tanh_arg, Expression::integer(2));
142 Expression::add(vec![
143 Expression::integer(1),
144 Expression::mul(vec![Expression::integer(-1), tanh_squared]),
145 ])
146 }),
147 },
148 result_template: "1 - tanh²(x)".to_owned(),
149 }),
150 antiderivative_rule: Some(AntiderivativeRule {
151 rule_type: AntiderivativeRuleType::Custom {
152 builder: Arc::new(|var: Symbol| {
153 Expression::function(
154 "ln",
155 vec![Expression::function("cosh", vec![Expression::symbol(var)])],
156 )
157 }),
158 },
159 result_template: "∫tanh(x)dx = ln(cosh(x)) + C".to_owned(),
160 constant_handling: ConstantOfIntegration::AddConstant,
161 }),
162 special_values: vec![SpecialValue {
163 input: "0".to_owned(),
164 output: Expression::integer(0),
165 latex_explanation: "\\tanh(0) = 0".to_owned(),
166 }],
167 identities: Box::new(vec![MathIdentity {
168 name: "Hyperbolic Tangent Identity".to_owned(),
169 lhs: Expression::function("tanh", vec![Expression::symbol("x")]),
170 rhs: Expression::function("sinh_over_cosh", vec![Expression::symbol("x")]),
171 conditions: vec!["x ∈ ℝ".to_owned()],
172 }]),
173 domain_range: Box::new(DomainRangeData {
174 domain: Domain::Real,
175 range: Range::Bounded(Expression::integer(-1), Expression::integer(1)),
176 singularities: vec![],
177 }),
178 periodicity: None,
179 wolfram_name: None,
180 })),
181 );
182 }
183
184 fn initialize_extended(&mut self) {
186 self.properties.insert(
187 "sech".to_owned(),
188 FunctionProperties::Elementary(Box::new(ElementaryProperties {
189 derivative_rule: Some(DerivativeRule {
190 rule_type: DerivativeRuleType::Custom {
191 builder: Arc::new(|arg: &Expression| {
192 let sech_arg = Expression::function("sech", vec![arg.clone()]);
193 let tanh_arg = Expression::function("tanh", vec![arg.clone()]);
194 Expression::mul(vec![Expression::integer(-1), sech_arg, tanh_arg])
195 }),
196 },
197 result_template: "-sech(x)·tanh(x)".to_owned(),
198 }),
199 antiderivative_rule: None,
200 special_values: vec![SpecialValue {
201 input: "0".to_owned(),
202 output: Expression::integer(1),
203 latex_explanation: "\\text{sech}(0) = 1".to_owned(),
204 }],
205 identities: Box::new(vec![]),
206 domain_range: Box::new(DomainRangeData {
207 domain: Domain::Real,
208 range: Range::Bounded(Expression::integer(0), Expression::integer(1)),
209 singularities: vec![],
210 }),
211 periodicity: None,
212 wolfram_name: None,
213 })),
214 );
215
216 self.properties.insert(
217 "csch".to_owned(),
218 FunctionProperties::Elementary(Box::new(ElementaryProperties {
219 derivative_rule: Some(DerivativeRule {
220 rule_type: DerivativeRuleType::Custom {
221 builder: Arc::new(|arg: &Expression| {
222 let csch_arg = Expression::function("csch", vec![arg.clone()]);
223 let coth_arg = Expression::function("coth", vec![arg.clone()]);
224 Expression::mul(vec![Expression::integer(-1), csch_arg, coth_arg])
225 }),
226 },
227 result_template: "-csch(x)·coth(x)".to_owned(),
228 }),
229 antiderivative_rule: None,
230 special_values: vec![],
231 identities: Box::new(vec![]),
232 domain_range: Box::new(DomainRangeData {
233 domain: Domain::Real,
234 range: Range::Real,
235 singularities: vec![Expression::integer(0)],
236 }),
237 periodicity: None,
238 wolfram_name: None,
239 })),
240 );
241
242 self.properties.insert(
243 "coth".to_owned(),
244 FunctionProperties::Elementary(Box::new(ElementaryProperties {
245 derivative_rule: Some(DerivativeRule {
246 rule_type: DerivativeRuleType::Custom {
247 builder: Arc::new(|arg: &Expression| {
248 let csch_arg = Expression::function("csch", vec![arg.clone()]);
249 let csch_squared = Expression::pow(csch_arg, Expression::integer(2));
250 Expression::add(vec![
251 Expression::integer(1),
252 Expression::mul(vec![Expression::integer(-1), csch_squared]),
253 ])
254 }),
255 },
256 result_template: "1 - csch²(x)".to_owned(),
257 }),
258 antiderivative_rule: None,
259 special_values: vec![],
260 identities: Box::new(vec![]),
261 domain_range: Box::new(DomainRangeData {
262 domain: Domain::Real,
263 range: Range::Real,
264 singularities: vec![Expression::integer(0)],
265 }),
266 periodicity: None,
267 wolfram_name: None,
268 })),
269 );
270 }
271
272 fn initialize_inverse(&mut self) {
274 self.properties.insert(
275 "asinh".to_owned(),
276 FunctionProperties::Elementary(Box::new(ElementaryProperties {
277 derivative_rule: Some(DerivativeRule {
278 rule_type: DerivativeRuleType::Custom {
279 builder: Arc::new(|arg: &Expression| {
280 let sqrt_term = Expression::function(
281 "sqrt",
282 vec![Expression::add(vec![
283 Expression::pow(arg.clone(), Expression::integer(2)),
284 Expression::integer(1),
285 ])],
286 );
287 Expression::mul(vec![
288 Expression::integer(1),
289 Expression::pow(sqrt_term, Expression::integer(-1)),
290 ])
291 }),
292 },
293 result_template: "1/√(x²+1)".to_owned(),
294 }),
295 antiderivative_rule: None,
296 special_values: vec![SpecialValue {
297 input: "0".to_owned(),
298 output: Expression::integer(0),
299 latex_explanation: "\\text{asinh}(0) = 0".to_owned(),
300 }],
301 identities: Box::new(vec![]),
302 domain_range: Box::new(DomainRangeData {
303 domain: Domain::Real,
304 range: Range::Real,
305 singularities: vec![],
306 }),
307 periodicity: None,
308 wolfram_name: None,
309 })),
310 );
311
312 self.properties.insert(
313 "acosh".to_owned(),
314 FunctionProperties::Elementary(Box::new(ElementaryProperties {
315 derivative_rule: Some(DerivativeRule {
316 rule_type: DerivativeRuleType::Custom {
317 builder: Arc::new(|arg: &Expression| {
318 let sqrt_term = Expression::function(
319 "sqrt",
320 vec![Expression::add(vec![
321 Expression::pow(arg.clone(), Expression::integer(2)),
322 Expression::integer(-1),
323 ])],
324 );
325 Expression::mul(vec![
326 Expression::integer(1),
327 Expression::pow(sqrt_term, Expression::integer(-1)),
328 ])
329 }),
330 },
331 result_template: "1/√(x²-1)".to_owned(),
332 }),
333 antiderivative_rule: None,
334 special_values: vec![SpecialValue {
335 input: "1".to_owned(),
336 output: Expression::integer(0),
337 latex_explanation: "\\text{acosh}(1) = 0".to_owned(),
338 }],
339 identities: Box::new(vec![]),
340 domain_range: Box::new(DomainRangeData {
341 domain: Domain::Real,
342 range: Range::Unbounded,
343 singularities: vec![],
344 }),
345 periodicity: None,
346 wolfram_name: None,
347 })),
348 );
349
350 self.properties.insert(
351 "atanh".to_owned(),
352 FunctionProperties::Elementary(Box::new(ElementaryProperties {
353 derivative_rule: Some(DerivativeRule {
354 rule_type: DerivativeRuleType::Custom {
355 builder: Arc::new(|arg: &Expression| {
356 let arg_squared = Expression::pow(arg.clone(), Expression::integer(2));
357 let denominator = Expression::add(vec![
358 Expression::integer(1),
359 Expression::mul(vec![Expression::integer(-1), arg_squared]),
360 ]);
361 Expression::mul(vec![
362 Expression::integer(1),
363 Expression::pow(denominator, Expression::integer(-1)),
364 ])
365 }),
366 },
367 result_template: "1/(1-x²)".to_owned(),
368 }),
369 antiderivative_rule: None,
370 special_values: vec![SpecialValue {
371 input: "0".to_owned(),
372 output: Expression::integer(0),
373 latex_explanation: "\\text{atanh}(0) = 0".to_owned(),
374 }],
375 identities: Box::new(vec![]),
376 domain_range: Box::new(DomainRangeData {
377 domain: Domain::Interval(Expression::integer(-1), Expression::integer(1)),
378 range: Range::Real,
379 singularities: vec![Expression::integer(-1), Expression::integer(1)],
380 }),
381 periodicity: None,
382 wolfram_name: None,
383 })),
384 );
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391
392 #[test]
393 fn test_hyperbolic_intelligence() {
394 let hyp = HyperbolicIntelligence::new();
395
396 assert!(hyp.has_function("sinh"));
397 assert!(hyp.has_function("cosh"));
398 assert!(hyp.has_function("tanh"));
399 assert!(hyp.has_function("sech"));
400 assert!(hyp.has_function("csch"));
401 assert!(hyp.has_function("coth"));
402 assert!(hyp.has_function("asinh"));
403 assert!(hyp.has_function("acosh"));
404 assert!(hyp.has_function("atanh"));
405 assert!(!hyp.has_function("sin"));
406
407 let properties = hyp.get_properties();
408 assert_eq!(properties.len(), 9);
409 }
410
411 #[test]
412 fn test_hyperbolic_derivative_rules() {
413 let hyp = HyperbolicIntelligence::new();
414 let properties = hyp.get_properties();
415
416 if let Some(FunctionProperties::Elementary(tanh_props)) = properties.get("tanh") {
417 assert!(tanh_props.derivative_rule.is_some());
418 let deriv = tanh_props.derivative_rule.as_ref().unwrap();
419 assert!(matches!(deriv.rule_type, DerivativeRuleType::Custom { .. }));
420 } else {
421 panic!("tanh properties not found");
422 }
423
424 if let Some(FunctionProperties::Elementary(asinh_props)) = properties.get("asinh") {
425 assert!(asinh_props.derivative_rule.is_some());
426 let deriv = asinh_props.derivative_rule.as_ref().unwrap();
427 assert!(matches!(deriv.rule_type, DerivativeRuleType::Custom { .. }));
428 } else {
429 panic!("asinh properties not found");
430 }
431 }
432}