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}