#![allow(dead_code)]
use {
coorder::Coord,
exterior::ExteriorElement,
glatt::field::DiffFormClosure,
multiindex::{Combination, Sign},
};
pub fn algebraic_convergence_rate(next: f64, prev: f64) -> f64 {
let quot: f64 = next / prev;
-quot.log2()
}
pub mod report {
pub const NA: &str = "—";
pub fn err(x: Option<f64>) -> String {
x.map_or_else(|| NA.to_string(), |x| format!("{x:.2e}"))
}
pub fn rate(r: Option<f64>) -> String {
match r {
Some(r) if r.is_finite() => format!("{r:.2}"),
_ => NA.to_string(),
}
}
pub fn eigval(lambda: f64) -> String {
let s = format!("{lambda:.3}");
if s == "-0.000" {
"0.000".to_string()
} else {
s
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BoundaryCondition {
Absolute,
Relative,
}
impl BoundaryCondition {
pub fn label(self) -> &'static str {
match self {
Self::Absolute => "absolute",
Self::Relative => "relative",
}
}
}
pub struct BoxEigenform {
pub dim: usize,
pub grade: usize,
pub bc: BoundaryCondition,
}
impl BoxEigenform {
pub fn new(dim: usize, grade: usize, bc: BoundaryCondition) -> Self {
assert!(grade <= dim);
Self { dim, grade, bc }
}
pub fn eigenvalue(&self) -> f64 {
self.dim as f64
}
pub fn solution(&self) -> DiffFormClosure {
let (dim, grade, relative) = (self.dim, self.grade, self.relative());
let blade = Combination::from_increasing(0..grade);
DiffFormClosure::new(
move |p: &Coord| {
bump(p, grade, relative) * ExteriorElement::from_blade_signed(dim, Sign::Pos, blade)
},
dim,
grade,
)
}
pub fn load(&self) -> DiffFormClosure {
let (dim, grade, relative) = (self.dim, self.grade, self.relative());
let lambda = self.eigenvalue();
let blade = Combination::from_increasing(0..grade);
DiffFormClosure::new(
move |p: &Coord| {
(lambda * bump(p, grade, relative))
* ExteriorElement::from_blade_signed(dim, Sign::Pos, blade)
},
dim,
grade,
)
}
pub fn dif_solution(&self) -> Option<DiffFormClosure> {
if self.grade == self.dim {
return None;
}
let (dim, grade, relative) = (self.dim, self.grade, self.relative());
let blade = Combination::from_increasing(0..grade);
Some(DiffFormClosure::new(
move |p: &Coord| {
let e_blade = ExteriorElement::from_blade_signed(dim, Sign::Pos, blade);
(0..dim)
.map(|j| {
let e_j =
ExteriorElement::from_blade_signed(dim, Sign::Pos, Combination::from_increasing([j]));
bump_partial(p, grade, j, relative) * e_j.wedge(&e_blade)
})
.sum()
},
dim,
grade + 1,
))
}
fn relative(&self) -> bool {
self.bc == BoundaryCondition::Relative
}
}
fn is_sin(i: usize, grade: usize, relative: bool) -> bool {
(i < grade) != relative
}
fn bump(p: &Coord, grade: usize, relative: bool) -> f64 {
p.iter()
.enumerate()
.map(|(i, &x)| {
if is_sin(i, grade, relative) {
x.sin()
} else {
x.cos()
}
})
.product()
}
fn bump_partial(p: &Coord, grade: usize, j: usize, relative: bool) -> f64 {
p.iter()
.enumerate()
.map(|(i, &x)| match (i == j, is_sin(i, grade, relative)) {
(true, true) => x.cos(),
(true, false) => -x.sin(),
(false, true) => x.sin(),
(false, false) => x.cos(),
})
.product()
}