use crate::matrix::MAX_SMALL_COLS;
use crate::small::{SmallMat, SmallVec};
use crate::Scalar;
pub type TableauMat<T> = SmallMat<T, { MAX_SMALL_COLS * MAX_SMALL_COLS }>;
pub type TableauVec<T> = SmallVec<T, MAX_SMALL_COLS>;
#[derive(Clone, Copy, Debug)]
pub struct Tableau<T: Scalar> {
a_t: TableauMat<T>,
b: TableauVec<T>,
c: TableauVec<T>,
d: TableauVec<T>,
order: usize,
beta_t: Option<TableauMat<T>>,
}
impl<T: Scalar> Tableau<T> {
pub fn tr_bdf2() -> Self {
let gamma = T::from_f64(2.0 - 2.0_f64.sqrt()).unwrap();
let d = gamma / T::from_f64(2.0).unwrap();
let w = T::from_f64(2.0_f64.sqrt() / 4.0).unwrap();
let a = TableauMat::from_slice(
3,
3,
&[T::zero(), d, w, T::zero(), d, w, T::zero(), T::zero(), d],
);
let b = TableauVec::from_slice(&[w, w, d]);
let b_hat = [
(T::one() - w) / T::from_f64(3.0).unwrap(),
(T::from_f64(3.0).unwrap() * w + T::one()) / T::from_f64(3.0).unwrap(),
d / T::from_f64(3.0).unwrap(),
];
let mut d_vec = TableauVec::zeros(3);
for (i, b_hat_i) in b_hat.iter().enumerate() {
d_vec[i] = b[i] - *b_hat_i;
}
let beta = TableauMat::from_slice(
3,
2,
&[
T::from_f64(2.0).unwrap() * w,
T::from_f64(2.0).unwrap() * w,
gamma - T::one(),
-w,
-w,
T::from_f64(2.0).unwrap() * w,
],
);
let c = TableauVec::from_slice(&[T::zero(), gamma, T::one()]);
let order = 2;
Self::new(a, b, c, d_vec, order, Some(beta))
}
pub fn esdirk34() -> Self {
let gamma = T::from_f64(0.435_866_521_508_459).unwrap();
let a = TableauMat::from_slice(
4,
4,
&[
T::zero(),
gamma,
T::from_f64(0.140_737_774_724_706_2).unwrap(),
T::from_f64(0.102_399_400_619_911).unwrap(),
T::zero(),
gamma,
T::from_f64(-0.108_365_551_381_320_8).unwrap(),
T::from_f64(-0.376_878_452_255_556_1).unwrap(),
T::zero(),
T::zero(),
gamma,
T::from_f64(0.838_612_530_127_186_1).unwrap(),
T::zero(),
T::zero(),
T::zero(),
gamma,
],
);
let b = TableauVec::from_slice(&[a[(3, 0)], a[(3, 1)], a[(3, 2)], a[(3, 3)]]);
let c = TableauVec::from_slice(&[
T::zero(),
T::from_f64(0.871_733_043_016_918).unwrap(),
T::from_f64(0.468_238_744_851_844_4).unwrap(),
T::one(),
]);
let d = TableauVec::from_slice(&[
T::from_f64(-0.054_625_497_240_413_94).unwrap(),
T::from_f64(-0.494_208_893_625_994_96).unwrap(),
T::from_f64(0.221_934_499_735_064_66).unwrap(),
T::from_f64(0.326_899_891_131_344_27).unwrap(),
]);
Self::new(a, b, c, d, 3, None)
}
pub fn tsit45() -> Self {
let c = TableauVec::from_slice(&[
T::zero(),
T::from_f64(0.161).unwrap(),
T::from_f64(0.327).unwrap(),
T::from_f64(0.9).unwrap(),
T::from_f64(0.9800255409045097).unwrap(),
T::one(),
T::one(),
]);
let b = TableauVec::from_slice(&[
T::from_f64(0.09646076681806523).unwrap(),
T::from_f64(0.01).unwrap(),
T::from_f64(0.4798896504144996).unwrap(),
T::from_f64(1.379008574103742).unwrap(),
T::from_f64(-3.290069515436081).unwrap(),
T::from_f64(2.324710524099774).unwrap(),
T::zero(),
]);
let d = TableauVec::from_slice(&[
T::from_f64(-0.001_780_011_052_225_777).unwrap(),
T::from_f64(-0.0008164344596567469).unwrap(),
T::from_f64(0.007880878010261995).unwrap(),
T::from_f64(-0.1447110071732629).unwrap(),
T::from_f64(0.5823571654525552).unwrap(),
T::from_f64(-0.45808210592918697).unwrap(),
T::from_f64(0.015151515151515152).unwrap(),
]);
let mut a = TableauMat::zeros(7, 7);
a[(2, 1)] = T::from_f64(0.335_480_655_492_357).unwrap();
a[(3, 1)] = T::from_f64(-6.359448489975075).unwrap();
a[(4, 1)] = T::from_f64(-11.74888356406283).unwrap();
a[(5, 1)] = T::from_f64(-12.92096931784711).unwrap();
a[(3, 2)] = T::from_f64(4.362295432869581).unwrap();
a[(4, 2)] = T::from_f64(7.495539342889836).unwrap();
a[(5, 2)] = T::from_f64(8.159367898576159).unwrap();
a[(4, 3)] = T::from_f64(-0.09249506636175525).unwrap();
a[(5, 3)] = T::from_f64(-0.071_584_973_281_401).unwrap();
a[(5, 4)] = T::from_f64(-0.02826905039406838).unwrap();
for i in 1..7 {
let mut a_sum = T::zero();
for j in 1..i {
a_sum += a[(i, j)];
}
a[(i, 0)] = c[i] - a_sum;
}
for j in 0..6 {
a[(6, j)] = b[j];
}
let beta = TableauMat::from_slice(
7,
4,
&[
T::one(),
T::zero(),
T::zero(),
T::zero(),
T::zero(),
T::zero(),
T::zero(),
T::from_f64(-2.76370619727483).unwrap(),
T::from_f64(0.1317).unwrap(),
T::from_f64(3.93029623689475).unwrap(),
T::from_f64(-12.4110771669337).unwrap(),
T::from_f64(37.509313416511).unwrap(),
T::from_f64(-27.8965262891973).unwrap(),
T::from_f64(1.5).unwrap(),
T::from_f64(2.91325546182191).unwrap(),
T::from_f64(-0.2234).unwrap(),
T::from_f64(-5.9410338721315).unwrap(),
T::from_f64(30.3381886302823).unwrap(),
T::from_f64(-88.1789048947664).unwrap(),
T::from_f64(65.0918946747937).unwrap(),
T::from_f64(-4.0).unwrap(),
T::from_f64(-1.05308849772902).unwrap(),
T::from_f64(0.1017).unwrap(),
T::from_f64(2.49062728565125).unwrap(),
T::from_f64(-16.5481028892449).unwrap(),
T::from_f64(47.3795219628193).unwrap(),
T::from_f64(-34.8706578614966).unwrap(),
T::from_f64(2.5).unwrap(),
],
);
let order = 4;
Self::new(a, b, c, d, order, Some(beta))
}
pub fn new(
a: TableauMat<T>,
b: TableauVec<T>,
c: TableauVec<T>,
d: TableauVec<T>,
order: usize,
beta: Option<TableauMat<T>>,
) -> Self {
let s = c.len();
assert!(
s <= MAX_SMALL_COLS,
"Invalid tableau, at most {MAX_SMALL_COLS} stages are supported"
);
assert_eq!(a.ncols(), s, "Invalid number of rows in a, expected {s}");
assert_eq!(a.nrows(), s, "Invalid number of columns in a, expected {s}",);
assert_eq!(b.len(), s, "Invalid number of elements in b, expected {s}",);
assert_eq!(d.len(), s, "Invalid number of elements in d, expected {s}",);
if let Some(beta) = &beta {
assert_eq!(
beta.nrows(),
s,
"Invalid number of rows in beta, expected {s}",
);
}
Self {
a_t: a.transposed(),
b,
c,
d,
order,
beta_t: beta.map(|beta| beta.transposed()),
}
}
pub fn order(&self) -> usize {
self.order
}
pub fn s(&self) -> usize {
self.c.len()
}
pub fn a(&self, i: usize, j: usize) -> T {
self.a_t[(j, i)]
}
pub fn stage_coeffs(&self, i: usize) -> &[T] {
&self.a_t.as_col_slice(i)[..i]
}
pub fn b(&self) -> &TableauVec<T> {
&self.b
}
pub fn c(&self) -> &TableauVec<T> {
&self.c
}
pub fn d(&self) -> &TableauVec<T> {
&self.d
}
pub fn beta_t(&self) -> Option<&TableauMat<T>> {
self.beta_t.as_ref()
}
}