mathhook_core/calculus/pde/common/
eigenvalues.rs

1//! Eigenvalue computation for standard boundary value problems
2
3use crate::calculus::pde::common::extract_domain_length;
4use crate::calculus::pde::registry::PDEError;
5use crate::calculus::pde::types::BoundaryCondition;
6use crate::core::{Expression, Symbol};
7
8/// Computes eigenvalues for 1D Dirichlet boundary conditions (heat equation form).
9///
10/// For domain [0, L] with homogeneous Dirichlet boundary conditions:
11/// u(0,t) = 0, u(L,t) = 0
12///
13/// The eigenvalues are: λₙ = (nπ/L)² for n = 1, 2, 3, ...
14///
15/// # Arguments
16/// * `boundary_conditions` - Boundary conditions (used to extract domain length)
17/// * `spatial_var` - Spatial variable symbol
18/// * `max_terms` - Maximum number of eigenvalues to compute
19///
20/// # Returns
21/// Vector of eigenvalue expressions λ₁, λ₂, ..., λₙ
22///
23/// # Examples
24/// ```rust
25/// use mathhook_core::calculus::pde::common::compute_dirichlet_1d_eigenvalues;
26/// use mathhook_core::symbol;
27///
28/// let x = symbol!(x);
29/// let bcs = vec![];
30/// let eigenvalues = compute_dirichlet_1d_eigenvalues(&bcs, &x, 5).unwrap();
31/// assert_eq!(eigenvalues.len(), 5);
32/// ```
33pub fn compute_dirichlet_1d_eigenvalues(
34    boundary_conditions: &[BoundaryCondition],
35    spatial_var: &Symbol,
36    max_terms: usize,
37) -> Result<Vec<Expression>, PDEError> {
38    if boundary_conditions.is_empty() {
39        let eigenvalues: Vec<_> = (1..=max_terms)
40            .map(|n| Expression::integer(n as i64))
41            .collect();
42        return Ok(eigenvalues);
43    }
44
45    let domain_length = extract_domain_length(boundary_conditions, spatial_var)?;
46
47    let eigenvalues: Vec<_> = (1..=max_terms)
48        .map(|n| {
49            let n_expr = Expression::integer(n as i64);
50            let pi = Expression::pi();
51
52            Expression::pow(
53                Expression::mul(vec![
54                    n_expr,
55                    pi,
56                    Expression::pow(domain_length.clone(), Expression::integer(-1)),
57                ]),
58                Expression::integer(2),
59            )
60        })
61        .collect();
62
63    Ok(eigenvalues)
64}
65
66/// Computes eigenvalues for 1D Dirichlet boundary conditions (wave equation form).
67///
68/// For domain [0, L] with homogeneous Dirichlet boundary conditions:
69/// u(0,t) = 0, u(L,t) = 0
70///
71/// The eigenvalues are: λₙ = nπ/L for n = 1, 2, 3, ...
72///
73/// # Arguments
74/// * `boundary_conditions` - Boundary conditions (used to extract domain length)
75/// * `spatial_var` - Spatial variable symbol
76/// * `max_terms` - Maximum number of eigenvalues to compute
77///
78/// # Returns
79/// Vector of eigenvalue expressions λ₁, λ₂, ..., λₙ
80///
81/// # Examples
82/// ```rust
83/// use mathhook_core::calculus::pde::common::compute_wave_eigenvalues;
84/// use mathhook_core::symbol;
85///
86/// let x = symbol!(x);
87/// let bcs = vec![];
88/// let eigenvalues = compute_wave_eigenvalues(&bcs, &x, 5).unwrap();
89/// assert_eq!(eigenvalues.len(), 5);
90/// ```
91pub fn compute_wave_eigenvalues(
92    boundary_conditions: &[BoundaryCondition],
93    spatial_var: &Symbol,
94    max_terms: usize,
95) -> Result<Vec<Expression>, PDEError> {
96    if boundary_conditions.is_empty() {
97        let eigenvalues: Vec<_> = (1..=max_terms)
98            .map(|n| Expression::integer(n as i64))
99            .collect();
100        return Ok(eigenvalues);
101    }
102
103    let domain_length = extract_domain_length(boundary_conditions, spatial_var)?;
104
105    let eigenvalues: Vec<_> = (1..=max_terms)
106        .map(|n| {
107            let n_expr = Expression::integer(n as i64);
108            let pi = Expression::pi();
109
110            Expression::mul(vec![
111                n_expr,
112                pi,
113                Expression::pow(domain_length.clone(), Expression::integer(-1)),
114            ])
115        })
116        .collect();
117
118    Ok(eigenvalues)
119}