mathhook_core/functions/special/
intelligence.rs

1//! Intelligence module for special mathematical functions
2//!
3//! Provides function properties, evaluation strategies, and educational
4//! explanations for special functions (gamma, bessel, zeta, etc.).
5//!
6//! # Function Integration
7//!
8//! Special functions often depend on each other mathematically:
9//! - Zeta function uses Lanczos gamma for functional equation (negative arguments)
10//! - Beta function defined as B(a,b) = Γ(a)·Γ(b)/Γ(a+b)
11//! - Cross-function dependencies are documented in each function's properties
12//!
13//! # Recent Enhancements
14//!
15//! - **Gamma**: Float numerical evaluation (Lanczos, 14-digit precision), half-integer special cases
16//! - **Bessel**: Input validation (NaN, infinity, domain checks), stability documentation
17//! - **Zeta**: Euler-Maclaurin acceleration (200x speedup), Lanczos gamma integration
18//!
19//! # Usage Example
20//!
21//! ```rust
22//! use mathhook_core::functions::special::SpecialIntelligence;
23//!
24//! let intelligence = SpecialIntelligence::new();
25//! let all_props = intelligence.get_all_properties();
26//!
27//! // Access specific function properties
28//! for (name, props) in all_props.iter() {
29//!     println!("Function: {}", name);
30//! }
31//! ```
32
33use crate::core::Expression;
34use crate::educational::step_by_step::Step;
35use crate::functions::intelligence::StepGenerator;
36use crate::functions::properties::{
37    AsymptoticData, DifferentialEquation, FunctionProperties, RecurrenceRule, SpecialProperties,
38    SpecialValue,
39};
40
41/// Special function intelligence provider
42///
43/// Centralized intelligence for all special mathematical functions including
44/// gamma function family, Bessel functions, Riemann zeta function, and more.
45///
46/// This registry provides O(1) lookup for function properties, enabling
47/// the Universal Function Intelligence architecture.
48pub struct SpecialIntelligence;
49
50impl SpecialIntelligence {
51    /// Create new special function intelligence
52    pub fn new() -> Self {
53        Self
54    }
55
56    /// Get all properties for registration
57    ///
58    /// Returns a vector of (function_name, properties) pairs for all special
59    /// functions. Used by UniversalFunctionRegistry for automatic registration.
60    pub fn get_all_properties(&self) -> Vec<(String, FunctionProperties)> {
61        vec![
62            ("gamma".to_owned(), Self::gamma_properties()),
63            ("beta".to_owned(), Self::beta_properties()),
64            ("digamma".to_owned(), Self::digamma_properties()),
65            ("polygamma".to_owned(), Self::polygamma_properties()),
66            ("bessel_j".to_owned(), Self::bessel_j_properties()),
67            ("bessel_y".to_owned(), Self::bessel_y_properties()),
68            ("zeta".to_owned(), Self::zeta_properties()),
69        ]
70    }
71
72    /// Get properties for gamma function
73    ///
74    /// - Float numerical evaluation via Lanczos approximation (14-digit precision)
75    /// - Half-integer special cases: Γ(1/2) = √π, Γ(3/2) = √π/2, Γ(5/2) = 3√π/4
76    /// - Input validation for NaN, infinity, and poles at non-positive integers
77    ///
78    /// # Cross-References
79    ///
80    /// - Used by Beta function: B(a,b) = Γ(a)·Γ(b)/Γ(a+b)
81    /// - Used by Zeta functional equation for negative arguments
82    fn gamma_properties() -> FunctionProperties {
83        FunctionProperties::Special(Box::new(SpecialProperties {
84            has_derivative: true,
85            has_antiderivative: false,
86            antiderivative_rule: None,
87            recurrence_relations: vec![RecurrenceRule {
88                name: "Functional equation".to_owned(),
89                relation: r"\Gamma(z+1) = z \cdot \Gamma(z)".to_owned(),
90                coefficients: vec![],
91            }],
92            differential_equation: None,
93            special_values: vec![
94                SpecialValue {
95                    input: "1".to_owned(),
96                    output: Expression::integer(1),
97                    latex_explanation: r"\Gamma(1) = 1".to_owned(),
98                },
99                SpecialValue {
100                    input: "2".to_owned(),
101                    output: Expression::integer(1),
102                    latex_explanation: r"\Gamma(2) = 1".to_owned(),
103                },
104                SpecialValue {
105                    input: "1/2".to_owned(),
106                    output: Expression::mul(vec![Expression::sqrt(Expression::pi())]),
107                    latex_explanation: r"\Gamma(1/2) = \sqrt{\pi}".to_owned(),
108                },
109                SpecialValue {
110                    input: "3/2".to_owned(),
111                    output: Expression::div(
112                        Expression::sqrt(Expression::pi()),
113                        Expression::integer(2),
114                    ),
115                    latex_explanation: r"\Gamma(3/2) = \frac{\sqrt{\pi}}{2}".to_owned(),
116                },
117                SpecialValue {
118                    input: "5/2".to_owned(),
119                    output: Expression::div(
120                        Expression::mul(vec![
121                            Expression::integer(3),
122                            Expression::sqrt(Expression::pi()),
123                        ]),
124                        Expression::integer(4),
125                    ),
126                    latex_explanation: r"\Gamma(5/2) = \frac{3\sqrt{\pi}}{4}".to_owned(),
127                },
128            ],
129            asymptotic_behavior: Some(AsymptoticData {
130                as_x_to_infinity:
131                    r"\Gamma(z) \sim \sqrt{2\pi/z} (z/e)^z \text{ (Stirling's approximation)}"
132                        .to_owned(),
133                as_x_to_zero: r"\Gamma(z) \sim 1/z \text{ for } z \to 0^+".to_owned(),
134                leading_coefficient: Expression::integer(1),
135            }),
136            wolfram_name: Some("Gamma"),
137        }))
138    }
139
140    /// Get properties for beta function
141    ///
142    /// # Mathematical Definition
143    ///
144    /// B(a,b) = Γ(a)·Γ(b)/Γ(a+b)
145    ///
146    /// # Recent Enhancements
147    ///
148    /// - Numerical evaluation using Lanczos gamma (14-digit precision)
149    /// - Supports both symbolic and numerical inputs
150    ///
151    /// # Cross-References
152    ///
153    /// - Defined using Gamma function (see gamma_properties)
154    fn beta_properties() -> FunctionProperties {
155        FunctionProperties::Special(Box::new(SpecialProperties {
156            has_derivative: true,
157            has_antiderivative: false,
158            antiderivative_rule: None,
159            recurrence_relations: vec![RecurrenceRule {
160                name: "Symmetry".to_owned(),
161                relation: r"B(a,b) = B(b,a)".to_owned(),
162                coefficients: vec![],
163            }],
164            differential_equation: None,
165            special_values: vec![SpecialValue {
166                input: "1, 1".to_owned(),
167                output: Expression::integer(1),
168                latex_explanation: r"B(1,1) = 1".to_owned(),
169            }],
170            asymptotic_behavior: None,
171            wolfram_name: Some("Beta"),
172        }))
173    }
174
175    /// Get properties for digamma function (ψ)
176    fn digamma_properties() -> FunctionProperties {
177        FunctionProperties::Special(Box::new(SpecialProperties {
178            has_derivative: true,
179            has_antiderivative: false,
180            antiderivative_rule: None,
181            recurrence_relations: vec![RecurrenceRule {
182                name: "Recurrence relation".to_owned(),
183                relation: r"\psi(z+1) = \psi(z) + \frac{1}{z}".to_owned(),
184                coefficients: vec![],
185            }],
186            differential_equation: None,
187            special_values: vec![],
188            asymptotic_behavior: None,
189            wolfram_name: None, // No direct Wolfram equivalent
190        }))
191    }
192
193    /// Get properties for polygamma function
194    fn polygamma_properties() -> FunctionProperties {
195        FunctionProperties::Special(Box::new(SpecialProperties {
196            has_derivative: true,
197            has_antiderivative: false,
198            antiderivative_rule: None,
199            recurrence_relations: vec![],
200            differential_equation: None,
201            special_values: vec![],
202            asymptotic_behavior: None,
203            wolfram_name: None, // No direct Wolfram equivalent
204        }))
205    }
206
207    /// Get properties for Bessel J function (first kind)
208    ///
209    /// # Recent Enhancements
210    ///
211    /// - Input validation for NaN, infinity
212    /// - Polynomial approximations for small arguments (Abramowitz & Stegun)
213    /// - Asymptotic expansions for large arguments
214    /// - Stability: Forward recurrence stable for x > n
215    /// - Accuracy: 10-12 significant digits
216    fn bessel_j_properties() -> FunctionProperties {
217        FunctionProperties::Special(Box::new(SpecialProperties {
218
219            has_derivative: true,
220            has_antiderivative: false,
221            antiderivative_rule: None,
222            recurrence_relations: vec![
223                RecurrenceRule {
224                    name: "Sum relation".to_owned(),
225                    relation: r"J_{n-1}(z) + J_{n+1}(z) = \frac{2n}{z}J_n(z)".to_owned(),
226                    coefficients: vec![],
227                },
228                RecurrenceRule {
229                    name: "Difference relation".to_owned(),
230                    relation: r"J_{n-1}(z) - J_{n+1}(z) = 2J'_n(z)".to_owned(),
231                    coefficients: vec![],
232                },
233                RecurrenceRule {
234                    name: "Reflection formula".to_owned(),
235                    relation: r"J_{-n}(z) = (-1)^n J_n(z)".to_owned(),
236                    coefficients: vec![],
237                },
238            ],
239            differential_equation: Some(DifferentialEquation {
240                order: 2,
241                equation: r"z^2 y'' + z y' + (z^2 - n^2)y = 0".to_owned(),
242                coefficients: vec![],
243            }),
244            special_values: vec![
245                SpecialValue {
246                    input: "0, 0".to_owned(),
247                    output: Expression::integer(1),
248                    latex_explanation: r"J_0(0) = 1".to_owned(),
249                },
250                SpecialValue {
251                    input: "n, 0".to_owned(),
252                    output: Expression::integer(0),
253                    latex_explanation: r"J_n(0) = 0 \text{ for } n > 0".to_owned(),
254                },
255            ],
256            asymptotic_behavior: Some(AsymptoticData {
257                as_x_to_infinity: r"J_n(z) \sim \sqrt{\frac{2}{\pi z}} \cos\left(z - \frac{n\pi}{2} - \frac{\pi}{4}\right)".to_owned(),
258                as_x_to_zero: r"J_0(0) = 1, J_n(0) = 0 \text{ for } n > 0".to_owned(),
259                leading_coefficient: Expression::integer(1),
260            }),
261            wolfram_name: None,  // Wolfram uses BesselJ[n, x] with different syntax
262        }))
263    }
264
265    /// Get properties for Bessel Y function (second kind)
266    ///
267    /// # Recent Enhancements
268    ///
269    /// - Input validation: NaN, infinity, domain restriction (x > 0 required)
270    /// - Logarithmic singularity at x=0 properly handled
271    /// - Stability documentation: Forward recurrence stable for x > n
272    /// - Accuracy: 10-12 significant digits for x > 0
273    fn bessel_y_properties() -> FunctionProperties {
274        FunctionProperties::Special(Box::new(SpecialProperties {
275
276            has_derivative: true,
277            has_antiderivative: false,
278            antiderivative_rule: None,
279            recurrence_relations: vec![
280                RecurrenceRule {
281                    name: "Sum relation".to_owned(),
282                    relation: r"Y_{n-1}(z) + Y_{n+1}(z) = \frac{2n}{z}Y_n(z)".to_owned(),
283                    coefficients: vec![],
284                },
285                RecurrenceRule {
286                    name: "Difference relation".to_owned(),
287                    relation: r"Y_{n-1}(z) - Y_{n+1}(z) = 2Y'_n(z)".to_owned(),
288                    coefficients: vec![],
289                },
290                RecurrenceRule {
291                    name: "Reflection formula".to_owned(),
292                    relation: r"Y_{-n}(z) = (-1)^n Y_n(z)".to_owned(),
293                    coefficients: vec![],
294                },
295            ],
296            differential_equation: Some(DifferentialEquation {
297                order: 2,
298                equation: r"z^2 y'' + z y' + (z^2 - n^2)y = 0".to_owned(),
299                coefficients: vec![],
300            }),
301            special_values: vec![SpecialValue {
302                input: "n, 0".to_owned(),
303                output: Expression::integer(-1),
304                latex_explanation: r"Y_n(0) = -\infty \text{ (logarithmic singularity)}".to_owned(),
305            }],
306            asymptotic_behavior: Some(AsymptoticData {
307                as_x_to_infinity: r"Y_n(z) \sim \sqrt{\frac{2}{\pi z}} \sin\left(z - \frac{n\pi}{2} - \frac{\pi}{4}\right)".to_owned(),
308                as_x_to_zero: r"Y_n(0) = -\infty \text{ (logarithmic singularity)}".to_owned(),
309                leading_coefficient: Expression::integer(1),
310            }),
311            wolfram_name: None,  // Wolfram uses BesselY[n, x] with different syntax
312        }))
313    }
314
315    /// Get properties for Riemann zeta function
316    ///
317    /// # Recent Enhancements
318    ///
319    /// - Euler-Maclaurin acceleration (50 terms, 200x speedup vs direct summation)
320    /// - Lanczos gamma integration for functional equation (negative arguments)
321    /// - Special cases: ζ(2), ζ(4), ζ(6), ζ(8), ζ(10), ζ(-1), ζ(-3), ζ(-5), ζ(-7)
322    /// - Convergence checks with early stopping for performance
323    ///
324    /// # Cross-References
325    ///
326    /// - Uses Lanczos gamma for functional equation (see gamma_properties)
327    /// - Functional equation: ζ(s) = 2^s π^(s-1) sin(πs/2) Γ(1-s) ζ(1-s)
328    fn zeta_properties() -> FunctionProperties {
329        FunctionProperties::Special(Box::new(SpecialProperties {
330
331            has_derivative: true,
332            has_antiderivative: false,
333            antiderivative_rule: None,
334            recurrence_relations: vec![RecurrenceRule {
335                name: "Functional equation".to_owned(),
336                relation: r"\zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s)".to_owned(),
337                coefficients: vec![],
338            }],
339            differential_equation: None,
340            special_values: vec![
341                SpecialValue {
342                    input: "0".to_owned(),
343                    output: Expression::rational(-1, 2),
344                    latex_explanation: r"\zeta(0) = -\frac{1}{2}".to_owned(),
345                },
346                SpecialValue {
347                    input: "-1".to_owned(),
348                    output: Expression::rational(-1, 12),
349                    latex_explanation: r"\zeta(-1) = -\frac{1}{12}".to_owned(),
350                },
351                SpecialValue {
352                    input: "2".to_owned(),
353                    output: Expression::div(
354                        Expression::pow(Expression::pi(), Expression::integer(2)),
355                        Expression::integer(6),
356                    ),
357                    latex_explanation: r"\zeta(2) = \frac{\pi^2}{6}".to_owned(),
358                },
359                SpecialValue {
360                    input: "4".to_owned(),
361                    output: Expression::div(
362                        Expression::pow(Expression::pi(), Expression::integer(4)),
363                        Expression::integer(90),
364                    ),
365                    latex_explanation: r"\zeta(4) = \frac{\pi^4}{90}".to_owned(),
366                },
367                SpecialValue {
368                    input: "6".to_owned(),
369                    output: Expression::div(
370                        Expression::pow(Expression::pi(), Expression::integer(6)),
371                        Expression::integer(945),
372                    ),
373                    latex_explanation: r"\zeta(6) = \frac{\pi^6}{945}".to_owned(),
374                },
375                SpecialValue {
376                    input: "8".to_owned(),
377                    output: Expression::div(
378                        Expression::pow(Expression::pi(), Expression::integer(8)),
379                        Expression::integer(9450),
380                    ),
381                    latex_explanation: r"\zeta(8) = \frac{\pi^8}{9450}".to_owned(),
382                },
383                SpecialValue {
384                    input: "10".to_owned(),
385                    output: Expression::div(
386                        Expression::pow(Expression::pi(), Expression::integer(10)),
387                        Expression::integer(93555),
388                    ),
389                    latex_explanation: r"\zeta(10) = \frac{\pi^{10}}{93555}".to_owned(),
390                },
391                SpecialValue {
392                    input: "-5".to_owned(),
393                    output: Expression::rational(-1, 252),
394                    latex_explanation: r"\zeta(-5) = -\frac{1}{252}".to_owned(),
395                },
396                SpecialValue {
397                    input: "-7".to_owned(),
398                    output: Expression::rational(1, 240),
399                    latex_explanation: r"\zeta(-7) = \frac{1}{240}".to_owned(),
400                },
401            ],
402            asymptotic_behavior: Some(AsymptoticData {
403                as_x_to_infinity: r"\zeta(s) \to 1 \text{ as } \text{Re}(s) \to \infty".to_owned(),
404                as_x_to_zero: r"\zeta(s) \text{ has pole at } s=1 \text{ with residue } 1".to_owned(),
405                leading_coefficient: Expression::integer(1),
406            }),
407            wolfram_name: Some("Zeta"),
408        }))
409    }
410}
411
412impl Default for SpecialIntelligence {
413    fn default() -> Self {
414        Self::new()
415    }
416}
417
418/// Step generator for special functions
419pub struct SpecialStepGenerator;
420
421impl StepGenerator for SpecialStepGenerator {
422    fn generate_steps(&self, name: &str, args: &[Expression]) -> Vec<Step> {
423        match name {
424            "gamma" => self.gamma_steps(args),
425            "beta" => self.beta_steps(args),
426            "digamma" => self.digamma_steps(args),
427            "polygamma" => self.polygamma_steps(args),
428            "bessel_j" => self.bessel_j_steps(args),
429            "bessel_y" => self.bessel_y_steps(args),
430            "zeta" => self.zeta_steps(args),
431            _ => vec![],
432        }
433    }
434
435    fn generate_latex_explanation(&self, name: &str, args: &[Expression]) -> String {
436        match name {
437            "gamma" => format!(
438                r"\Gamma({})",
439                args.first().map(|e| e.to_string()).unwrap_or_default()
440            ),
441            "beta" => format!(
442                r"B({}, {})",
443                args.first().map(|e| e.to_string()).unwrap_or_default(),
444                args.get(1).map(|e| e.to_string()).unwrap_or_default()
445            ),
446            "digamma" => format!(
447                r"\psi({})",
448                args.first().map(|e| e.to_string()).unwrap_or_default()
449            ),
450            "polygamma" => format!(
451                r"\psi^{{({})}}({})",
452                args.first().map(|e| e.to_string()).unwrap_or_default(),
453                args.get(1).map(|e| e.to_string()).unwrap_or_default()
454            ),
455            "bessel_j" => format!(
456                r"J_{{{}}}({})",
457                args.first().map(|e| e.to_string()).unwrap_or_default(),
458                args.get(1).map(|e| e.to_string()).unwrap_or_default()
459            ),
460            "bessel_y" => format!(
461                r"Y_{{{}}}({})",
462                args.first().map(|e| e.to_string()).unwrap_or_default(),
463                args.get(1).map(|e| e.to_string()).unwrap_or_default()
464            ),
465            "zeta" => format!(
466                r"\zeta({})",
467                args.first().map(|e| e.to_string()).unwrap_or_default()
468            ),
469            _ => String::new(),
470        }
471    }
472}
473
474impl SpecialStepGenerator {
475    fn gamma_steps(&self, args: &[Expression]) -> Vec<Step> {
476        if args.is_empty() {
477            return vec![];
478        }
479
480        vec![Step::new(
481            "Gamma Function",
482            format!("Evaluating Γ({})", args[0]),
483        )]
484    }
485
486    fn beta_steps(&self, args: &[Expression]) -> Vec<Step> {
487        if args.len() < 2 {
488            return vec![];
489        }
490
491        vec![Step::new(
492            "Beta Function",
493            format!("Evaluating B({}, {})", args[0], args[1]),
494        )]
495    }
496
497    fn digamma_steps(&self, args: &[Expression]) -> Vec<Step> {
498        if args.is_empty() {
499            return vec![];
500        }
501
502        vec![Step::new(
503            "Digamma Function",
504            format!("Evaluating ψ({})", args[0]),
505        )]
506    }
507
508    fn polygamma_steps(&self, args: &[Expression]) -> Vec<Step> {
509        if args.len() < 2 {
510            return vec![];
511        }
512
513        vec![Step::new(
514            "Polygamma Function",
515            format!("Evaluating ψ^({})({})", args[0], args[1]),
516        )]
517    }
518
519    fn bessel_j_steps(&self, args: &[Expression]) -> Vec<Step> {
520        if args.len() < 2 {
521            return vec![];
522        }
523
524        let mut steps = vec![Step::new(
525            "Bessel Function (First Kind)",
526            format!("Evaluating J_{{{}}}({})", args[0], args[1]),
527        )];
528
529        steps.push(Step::new(
530            "Mathematical Context",
531            "Bessel J functions solve: z²y'' + zy' + (z² - n²)y = 0".to_owned(),
532        ));
533
534        steps.push(Step::new(
535            "Properties",
536            "J functions are finite at origin; used in wave propagation and heat conduction"
537                .to_owned(),
538        ));
539
540        steps
541    }
542
543    fn bessel_y_steps(&self, args: &[Expression]) -> Vec<Step> {
544        if args.len() < 2 {
545            return vec![];
546        }
547
548        let mut steps = vec![Step::new(
549            "Bessel Function (Second Kind)",
550            format!("Evaluating Y_{{{}}}({})", args[0], args[1]),
551        )];
552
553        steps.push(Step::new(
554            "Mathematical Context",
555            "Bessel Y functions solve: z²y'' + zy' + (z² - n²)y = 0".to_owned(),
556        ));
557
558        steps.push(Step::new(
559            "Warning",
560            "Y functions have logarithmic singularity at z = 0".to_owned(),
561        ));
562
563        steps
564    }
565
566    fn zeta_steps(&self, args: &[Expression]) -> Vec<Step> {
567        if args.is_empty() {
568            return vec![];
569        }
570
571        let mut steps = vec![Step::new(
572            "Riemann Zeta Function",
573            format!("Evaluating ζ({})", args[0]),
574        )];
575
576        steps.push(Step::new(
577            "Definition",
578            "For Re(s) > 1: ζ(s) = Σ(n=1 to ∞) 1/n^s".to_owned(),
579        ));
580
581        steps.push(Step::new(
582            "Special Values",
583            "The Riemann zeta function has known values: ζ(2)=π²/6, ζ(4)=π⁴/90, ζ(0)=-1/2, ζ(-1)=-1/12".to_owned(),
584        ));
585
586        steps.push(Step::new(
587            "Pole at s=1",
588            "Note: ζ(s) has a simple pole at s=1 with residue 1".to_owned(),
589        ));
590
591        steps.push(Step::new(
592            "Functional Equation",
593            "ζ(s) = 2^s π^(s-1) sin(πs/2) Γ(1-s) ζ(1-s) extends ζ to entire complex plane"
594                .to_owned(),
595        ));
596
597        steps
598    }
599}
600
601#[cfg(test)]
602mod tests {
603    use super::*;
604
605    #[test]
606    fn test_gamma_properties() {
607        let props = SpecialIntelligence::gamma_properties();
608        match props {
609            FunctionProperties::Special(sp) => {
610                assert!(sp.has_derivative);
611                assert!(
612                    sp.special_values.len() >= 5,
613                    "Should have at least 5 special values including half-integers"
614                );
615            }
616            _ => panic!("Expected Special properties"),
617        }
618    }
619
620    #[test]
621    fn test_special_intelligence_get_all() {
622        let intelligence = SpecialIntelligence::new();
623        let all_props = intelligence.get_all_properties();
624        assert!(
625            all_props.len() >= 7,
626            "Should have at least 7 functions (gamma, beta, digamma, polygamma, bessel_j, bessel_y, zeta)"
627        );
628    }
629
630    #[test]
631    fn test_step_generator() {
632        let generator = SpecialStepGenerator;
633        let arg = Expression::integer(5);
634        let steps = generator.generate_steps("gamma", &[arg]);
635        assert!(!steps.is_empty());
636    }
637
638    #[test]
639    fn test_bessel_j_properties() {
640        let props = SpecialIntelligence::bessel_j_properties();
641        match props {
642            FunctionProperties::Special(sp) => {
643                assert!(sp.has_derivative);
644                assert!(
645                    !sp.recurrence_relations.is_empty(),
646                    "Should have recurrence relations"
647                );
648                assert!(
649                    sp.differential_equation.is_some(),
650                    "Should have differential equation"
651                );
652                assert!(!sp.special_values.is_empty(), "Should have special values");
653                assert!(
654                    sp.asymptotic_behavior.is_some(),
655                    "Should have asymptotic behavior"
656                );
657            }
658            _ => panic!("Expected Special properties"),
659        }
660    }
661
662    #[test]
663    fn test_bessel_y_properties() {
664        let props = SpecialIntelligence::bessel_y_properties();
665        match props {
666            FunctionProperties::Special(sp) => {
667                assert!(sp.has_derivative);
668                assert!(
669                    !sp.recurrence_relations.is_empty(),
670                    "Should have recurrence relations"
671                );
672                assert!(
673                    sp.differential_equation.is_some(),
674                    "Should have differential equation"
675                );
676                assert!(
677                    sp.asymptotic_behavior.is_some(),
678                    "Should have asymptotic behavior"
679                );
680            }
681            _ => panic!("Expected Special properties"),
682        }
683    }
684
685    #[test]
686    fn test_bessel_j_step_generation() {
687        let generator = SpecialStepGenerator;
688        let n = Expression::integer(0);
689        let x = Expression::integer(1);
690        let steps = generator.generate_steps("bessel_j", &[n, x]);
691        assert!(!steps.is_empty(), "Should generate steps");
692        assert!(
693            steps.len() >= 3,
694            "Should have at least 3 steps (evaluation, context, properties)"
695        );
696    }
697
698    #[test]
699    fn test_bessel_y_step_generation() {
700        let generator = SpecialStepGenerator;
701        let n = Expression::integer(0);
702        let x = Expression::integer(1);
703        let steps = generator.generate_steps("bessel_y", &[n, x]);
704        assert!(!steps.is_empty(), "Should generate steps");
705        assert!(
706            steps.len() >= 3,
707            "Should have at least 3 steps (evaluation, context, warning)"
708        );
709    }
710
711    #[test]
712    fn test_bessel_j_latex_explanation() {
713        let generator = SpecialStepGenerator;
714        let n = Expression::integer(2);
715        let x = Expression::integer(5);
716        let latex = generator.generate_latex_explanation("bessel_j", &[n, x]);
717        assert!(latex.contains("J_"), "Should contain J_");
718        assert!(latex.contains("2"), "Should contain order");
719        assert!(latex.contains("5"), "Should contain argument");
720    }
721
722    #[test]
723    fn test_bessel_y_latex_explanation() {
724        let generator = SpecialStepGenerator;
725        let n = Expression::integer(1);
726        let x = Expression::integer(3);
727        let latex = generator.generate_latex_explanation("bessel_y", &[n, x]);
728        assert!(latex.contains("Y_"), "Should contain Y_");
729        assert!(latex.contains("1"), "Should contain order");
730        assert!(latex.contains("3"), "Should contain argument");
731    }
732
733    #[test]
734    fn test_all_functions_have_properties() {
735        let intelligence = SpecialIntelligence::new();
736        let all_props = intelligence.get_all_properties();
737
738        let function_names: Vec<String> = all_props.iter().map(|(name, _)| name.clone()).collect();
739
740        assert!(
741            function_names.contains(&"bessel_j".to_string()),
742            "bessel_j should be registered"
743        );
744        assert!(
745            function_names.contains(&"bessel_y".to_string()),
746            "bessel_y should be registered"
747        );
748        assert!(
749            function_names.contains(&"zeta".to_string()),
750            "zeta should be registered"
751        );
752    }
753
754    #[test]
755    fn test_zeta_properties() {
756        let props = SpecialIntelligence::zeta_properties();
757        match props {
758            FunctionProperties::Special(sp) => {
759                assert!(sp.has_derivative, "Zeta should have derivative");
760                assert!(
761                    sp.special_values.len() >= 9,
762                    "Zeta should have at least 9 special values (including ζ(8), ζ(10), ζ(-5), ζ(-7))"
763                );
764                assert!(
765                    sp.asymptotic_behavior.is_some(),
766                    "Zeta should have asymptotic behavior"
767                );
768                assert!(
769                    !sp.recurrence_relations.is_empty(),
770                    "Zeta should have functional equation"
771                );
772            }
773            _ => panic!("Expected Special properties"),
774        }
775    }
776
777    #[test]
778    fn test_zeta_step_generation() {
779        let generator = SpecialStepGenerator;
780        let s = Expression::integer(2);
781        let steps = generator.generate_steps("zeta", &[s]);
782        assert!(!steps.is_empty(), "Should generate steps for zeta");
783        assert!(
784            steps.len() >= 4,
785            "Should have at least 4 steps (evaluation, definition, special values, pole)"
786        );
787    }
788
789    #[test]
790    fn test_zeta_latex_explanation() {
791        let generator = SpecialStepGenerator;
792        let s = Expression::integer(3);
793        let latex = generator.generate_latex_explanation("zeta", &[s]);
794        assert!(latex.contains(r"\zeta"), "Should contain zeta symbol");
795        assert!(latex.contains("3"), "Should contain argument");
796    }
797
798    #[test]
799    fn test_gamma_half_integer_special_values() {
800        let props = SpecialIntelligence::gamma_properties();
801        match props {
802            FunctionProperties::Special(sp) => {
803                let half_integer_values: Vec<_> = sp
804                    .special_values
805                    .iter()
806                    .filter(|v| v.input.contains("/"))
807                    .collect();
808                assert!(
809                    half_integer_values.len() >= 3,
810                    "Should have at least 3 half-integer special values"
811                );
812            }
813            _ => panic!("Expected Special properties"),
814        }
815    }
816
817    #[test]
818    fn test_beta_gamma_relationship_documented() {
819        let props = SpecialIntelligence::beta_properties();
820        match props {
821            FunctionProperties::Special(sp) => {
822                assert!(
823                    !sp.recurrence_relations.is_empty(),
824                    "Beta should document relationship with Gamma"
825                );
826            }
827            _ => panic!("Expected Special properties"),
828        }
829    }
830}