pub use crate::functions::polynomials::{
chebyshev, evaluation, hermite, laguerre, legendre, symbolic, PolynomialIntelligence,
};
pub use crate::functions::polynomials::evaluation::{
evaluate_chebyshev_first_numerical, evaluate_chebyshev_second_numerical,
evaluate_hermite_numerical, evaluate_laguerre_numerical, evaluate_legendre_numerical,
};
pub use crate::functions::polynomials::symbolic::{
expand_chebyshev_first_symbolic, expand_chebyshev_second_symbolic, expand_hermite_symbolic,
expand_laguerre_symbolic, expand_legendre_symbolic,
};
use crate::core::{Expression, Symbol};
use crate::pattern::Substitutable;
pub trait OrthogonalPolynomial {
fn polynomial(n: usize, var: &Symbol) -> Expression;
fn evaluate(n: usize, x: f64) -> f64;
fn recurrence_coefficients(n: usize) -> (f64, f64, f64);
}
pub struct Legendre;
impl OrthogonalPolynomial for Legendre {
fn polynomial(n: usize, var: &Symbol) -> Expression {
let expr = expand_legendre_symbolic(n);
if var.name() == "x" {
expr
} else {
expr.subs(&Expression::symbol("x"), &Expression::symbol(var.clone()))
}
}
fn evaluate(n: usize, x: f64) -> f64 {
let result = evaluate_legendre_numerical(&[n as f64, x]);
result.first().copied().unwrap_or(0.0)
}
fn recurrence_coefficients(n: usize) -> (f64, f64, f64) {
let n_f64 = n as f64;
let a_n = (2.0 * n_f64 + 1.0) / (n_f64 + 1.0);
let b_n = 0.0;
let c_n = n_f64 / (n_f64 + 1.0);
(a_n, b_n, c_n)
}
}
pub struct ChebyshevT;
impl OrthogonalPolynomial for ChebyshevT {
fn polynomial(n: usize, var: &Symbol) -> Expression {
let expr = expand_chebyshev_first_symbolic(n);
if var.name() == "x" {
expr
} else {
expr.subs(&Expression::symbol("x"), &Expression::symbol(var.clone()))
}
}
fn evaluate(n: usize, x: f64) -> f64 {
let result = evaluate_chebyshev_first_numerical(&[n as f64, x]);
result.first().copied().unwrap_or(0.0)
}
fn recurrence_coefficients(n: usize) -> (f64, f64, f64) {
if n == 0 {
(1.0, 0.0, 0.0)
} else {
(2.0, 0.0, 1.0)
}
}
}
pub struct ChebyshevU;
impl OrthogonalPolynomial for ChebyshevU {
fn polynomial(n: usize, var: &Symbol) -> Expression {
let expr = expand_chebyshev_second_symbolic(n);
if var.name() == "x" {
expr
} else {
expr.subs(&Expression::symbol("x"), &Expression::symbol(var.clone()))
}
}
fn evaluate(n: usize, x: f64) -> f64 {
let result = evaluate_chebyshev_second_numerical(&[n as f64, x]);
result.first().copied().unwrap_or(0.0)
}
fn recurrence_coefficients(n: usize) -> (f64, f64, f64) {
if n == 0 {
(2.0, 0.0, 0.0)
} else {
(2.0, 0.0, 1.0)
}
}
}
pub struct Hermite;
impl OrthogonalPolynomial for Hermite {
fn polynomial(n: usize, var: &Symbol) -> Expression {
let expr = expand_hermite_symbolic(n);
if var.name() == "x" {
expr
} else {
expr.subs(&Expression::symbol("x"), &Expression::symbol(var.clone()))
}
}
fn evaluate(n: usize, x: f64) -> f64 {
let result = evaluate_hermite_numerical(&[n as f64, x]);
result.first().copied().unwrap_or(0.0)
}
fn recurrence_coefficients(n: usize) -> (f64, f64, f64) {
let n_f64 = n as f64;
(2.0, 0.0, 2.0 * n_f64)
}
}
pub struct Laguerre;
impl OrthogonalPolynomial for Laguerre {
fn polynomial(n: usize, var: &Symbol) -> Expression {
let expr = expand_laguerre_symbolic(n);
if var.name() == "x" {
expr
} else {
expr.subs(&Expression::symbol("x"), &Expression::symbol(var.clone()))
}
}
fn evaluate(n: usize, x: f64) -> f64 {
let result = evaluate_laguerre_numerical(&[n as f64, x]);
result.first().copied().unwrap_or(0.0)
}
fn recurrence_coefficients(n: usize) -> (f64, f64, f64) {
let n_f64 = n as f64;
let a_n = -1.0 / (n_f64 + 1.0);
let b_n = (2.0 * n_f64 + 1.0) / (n_f64 + 1.0);
let c_n = n_f64 / (n_f64 + 1.0);
(a_n, b_n, c_n)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::symbol;
#[test]
fn test_legendre_base_cases() {
let x = symbol!(x);
let p0 = Legendre::polynomial(0, &x);
let p1 = Legendre::polynomial(1, &x);
assert_eq!(p0, Expression::integer(1));
assert_eq!(p1, Expression::symbol(x));
}
#[test]
fn test_legendre_eval() {
assert!((Legendre::evaluate(0, 0.5) - 1.0).abs() < 1e-10);
assert!((Legendre::evaluate(1, 0.5) - 0.5).abs() < 1e-10);
assert!((Legendre::evaluate(2, 0.5) - (-0.125)).abs() < 1e-10);
}
#[test]
fn test_chebyshev_t_base_cases() {
let x = symbol!(x);
let t0 = ChebyshevT::polynomial(0, &x);
let t1 = ChebyshevT::polynomial(1, &x);
assert_eq!(t0, Expression::integer(1));
assert_eq!(t1, Expression::symbol(x));
}
#[test]
fn test_chebyshev_t_eval() {
assert!((ChebyshevT::evaluate(0, 0.5) - 1.0).abs() < 1e-10);
assert!((ChebyshevT::evaluate(1, 0.5) - 0.5).abs() < 1e-10);
assert!((ChebyshevT::evaluate(2, 0.5) - (-0.5)).abs() < 1e-10);
}
#[test]
fn test_chebyshev_u_eval() {
assert!((ChebyshevU::evaluate(0, 0.5) - 1.0).abs() < 1e-10);
assert!((ChebyshevU::evaluate(1, 0.5) - 1.0).abs() < 1e-10);
}
#[test]
fn test_hermite_base_cases() {
let x = symbol!(x);
let h0 = Hermite::polynomial(0, &x);
let _h1 = Hermite::polynomial(1, &x);
assert_eq!(h0, Expression::integer(1));
}
#[test]
fn test_hermite_eval() {
assert!((Hermite::evaluate(0, 0.5) - 1.0).abs() < 1e-10);
assert!((Hermite::evaluate(1, 0.5) - 1.0).abs() < 1e-10);
}
#[test]
fn test_laguerre_base_cases() {
let x = symbol!(x);
let l0 = Laguerre::polynomial(0, &x);
assert_eq!(l0, Expression::integer(1));
}
#[test]
fn test_laguerre_eval() {
assert!((Laguerre::evaluate(0, 0.5) - 1.0).abs() < 1e-10);
assert!((Laguerre::evaluate(1, 0.5) - 0.5).abs() < 1e-10);
}
#[test]
fn test_recurrence_coefficients() {
let (a, b, c) = Legendre::recurrence_coefficients(2);
assert!(a > 0.0);
assert_eq!(b, 0.0);
assert!(c > 0.0);
let (a, _, c) = ChebyshevT::recurrence_coefficients(2);
assert_eq!(a, 2.0);
assert_eq!(c, 1.0);
}
#[test]
fn test_variable_substitution() {
let t = symbol!(t);
let p1 = Legendre::polynomial(1, &t);
assert_eq!(p1, Expression::symbol(t));
}
}