mathhook_core/calculus/pde/
classification.rs

1//! PDE classification algorithms
2//!
3//! **⚠️ IMPORTANT LIMITATIONS** (Version 0.1.0):
4//!
5//! This module currently uses **simplified heuristics** and is **NOT mathematically rigorous**.
6//! See `DESIGN_PROPER_CLASSIFICATION.md` for the planned proper implementation.
7//!
8//! # Current Implementation Status
9//!
10//! **❌ Known Issues**:
11//! 1. **No Coefficient Extraction**: Does not extract actual coefficients A, B, C from equations
12//! 2. **Heuristic Classification**: Uses expression structure (Add vs Mul) as proxy for PDE type
13//! 3. **Hardcoded Patterns**: Only works for specific well-known PDEs (heat, wave, Laplace)
14//! 4. **Invalid Discriminant**: Returns hardcoded values instead of computing B² - 4AC
15//!
16//! **Recommended Usage**:
17//! - ✅ Educational purposes with standard PDEs only
18//! - ❌ Do NOT use for arbitrary PDE classification
19//! - ❌ Do NOT rely on results for mathematical correctness
20//!
21//! # Proper Implementation (Planned v0.2.0)
22//!
23//! The proper implementation will:
24//! 1. Extract actual coefficients A, B, C from PDE equations
25//! 2. Compute true discriminant B² - 4AC
26//! 3. Use symbolic sign analysis for classification
27//! 4. Handle both constant and variable coefficient PDEs
28//!
29//! See `DESIGN_PROPER_CLASSIFICATION.md` for complete design specification.
30//!
31//! # Mathematical Foundation (Reference)
32//!
33//! For a second-order linear PDE: `A·u_xx + B·u_xy + C·u_yy + ... = G`
34//!
35//! Classification by discriminant Δ = B² - 4AC:
36//! - **Elliptic** (Δ < 0): Laplace equation, steady-state problems
37//! - **Parabolic** (Δ = 0): Heat equation, diffusion processes
38//! - **Hyperbolic** (Δ > 0): Wave equation, propagation phenomena
39//!
40//! **References**:
41//! - Evans, L. C. (2010). *Partial Differential Equations*. AMS.
42//! - Strauss, W. A. (2007). *Partial Differential Equations: An Introduction*. Wiley.
43
44mod linearity;
45mod type_detection;
46
47use crate::calculus::pde::types::{Pde, PdeLinearity, PdeOrder, PdeType};
48
49/// Classify a PDE and return its type
50pub fn classify_pde(pde: &Pde) -> Result<PdeType, String> {
51    if pde.order() != PdeOrder::Second {
52        return Err("Only second-order PDEs can be classified by type".to_owned());
53    }
54
55    pde.pde_type()
56        .ok_or_else(|| "Failed to classify PDE type".to_owned())
57}
58
59impl Pde {
60    /// Determine the order of the PDE
61    pub fn order(&self) -> PdeOrder {
62        let max_order = self.max_derivative_order();
63        match max_order {
64            0 | 1 => PdeOrder::First,
65            2 => PdeOrder::Second,
66            n => PdeOrder::Higher(n),
67        }
68    }
69
70    /// Determine the linearity classification
71    pub fn linearity(&self) -> PdeLinearity {
72        if self.is_linear() {
73            PdeLinearity::Linear
74        } else if self.is_quasilinear() {
75            PdeLinearity::Quasilinear
76        } else if self.is_semilinear() {
77            PdeLinearity::Semilinear
78        } else {
79            PdeLinearity::Nonlinear
80        }
81    }
82
83    /// Find maximum derivative order in the equation
84    fn max_derivative_order(&self) -> u32 {
85        let var_count = self.independent_vars.len() as u32;
86        if var_count >= 2 {
87            2
88        } else if var_count == 1 {
89            1
90        } else {
91            0
92        }
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use crate::{expr, symbol};
100
101    #[test]
102    fn test_classify_pde_second_order() {
103        let u = symbol!(u);
104        let x = symbol!(x);
105        let y = symbol!(y);
106        let equation = expr!(x + y);
107        let pde = Pde::new(equation, u, vec![x, y]);
108        let result = classify_pde(&pde);
109        assert!(result.is_ok());
110        assert_eq!(result.unwrap(), PdeType::Elliptic);
111    }
112
113    #[test]
114    fn test_classify_pde_first_order_fails() {
115        let u = symbol!(u);
116        let x = symbol!(x);
117        let equation = expr!(u);
118        let pde = Pde::new(equation, u, vec![x]);
119        let result = classify_pde(&pde);
120        assert!(result.is_err());
121    }
122
123    #[test]
124    fn test_pde_order_first() {
125        let u = symbol!(u);
126        let x = symbol!(x);
127        let equation = expr!(u);
128        let pde = Pde::new(equation, u, vec![x]);
129        assert_eq!(pde.order(), PdeOrder::First);
130    }
131
132    #[test]
133    fn test_pde_order_second() {
134        let u = symbol!(u);
135        let x = symbol!(x);
136        let y = symbol!(y);
137        let equation = expr!(x + y);
138        let pde = Pde::new(equation, u, vec![x, y]);
139        assert_eq!(pde.order(), PdeOrder::Second);
140    }
141
142    #[test]
143    fn test_pde_linearity_linear() {
144        let u = symbol!(u);
145        let x = symbol!(x);
146        let equation = expr!(u);
147        let pde = Pde::new(equation, u, vec![x]);
148        assert_eq!(pde.linearity(), PdeLinearity::Linear);
149    }
150
151    #[test]
152    fn test_pde_type_classification() {
153        let u = symbol!(u);
154        let x = symbol!(x);
155        let y = symbol!(y);
156        let equation = expr!(x + y);
157        let pde = Pde::new(equation, u, vec![x, y]);
158        assert_eq!(pde.pde_type(), Some(PdeType::Elliptic));
159    }
160
161    #[test]
162    fn test_max_derivative_order_single_var() {
163        let u = symbol!(u);
164        let x = symbol!(x);
165        let equation = expr!(u);
166        let pde = Pde::new(equation, u, vec![x]);
167        assert_eq!(pde.max_derivative_order(), 1);
168    }
169
170    #[test]
171    fn test_max_derivative_order_two_vars_addition() {
172        let u = symbol!(u);
173        let x = symbol!(x);
174        let y = symbol!(y);
175        let equation = expr!(x + y);
176        let pde = Pde::new(equation, u, vec![x, y]);
177        assert_eq!(pde.max_derivative_order(), 2);
178    }
179
180    #[test]
181    fn test_max_derivative_order_two_vars_multiplication() {
182        let u = symbol!(u);
183        let x = symbol!(x);
184        let y = symbol!(y);
185        let equation = expr!(x * y);
186        let pde = Pde::new(equation, u, vec![x, y]);
187        assert_eq!(pde.max_derivative_order(), 2);
188    }
189}