use crate::dd::DD;
use crate::dual::{Counted, Dc, Dtn, Du, Fu, Fun, Lane, Qu, F8};
use crate::dv::{DotAcc, DV};
use crate::jet::{Jet, QJet};
use crate::linalg::DDLu;
use crate::qd::QD;
use crate::qv::QV;
use crate::simd::Simd;
use crate::v8::V8;
use std::ops::{Add, Div, Mul, Neg, Sub};
#[derive(Clone, Copy, Debug)]
pub struct Fl<T: Lane, const B: usize>(pub [T; B]);
type Dv<T> = DV<<T as Lane>::S>;
macro_rules! fl_binop {
($tr:ident, $f:ident, $op:tt) => {
impl<T: Lane, const B: usize> $tr for Fl<T, B> {
type Output = Fl<T, B>;
#[inline(always)]
fn $f(self, o: Fl<T, B>) -> Fl<T, B> {
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b] $op o.0[b];
}
Fl(r)
}
}
};
}
fl_binop!(Add, add, +);
fl_binop!(Sub, sub, -);
fl_binop!(Mul, mul, *);
fl_binop!(Div, div, /);
impl<T: Lane, const B: usize> Neg for Fl<T, B> {
type Output = Fl<T, B>;
#[inline(always)]
fn neg(self) -> Fl<T, B> {
let mut r = self.0;
for b in 0..B {
r[b] = -self.0[b];
}
Fl(r)
}
}
impl<T: Lane, const B: usize> Fl<T, B> {
#[inline(always)]
pub fn zero() -> Self {
Fl([T::zero(); B])
}
#[inline(always)]
pub fn splat(x: DD) -> Self {
Fl([T::splat(x); B])
}
#[inline(always)]
pub fn cst(c: &Fl<Dv<T>, B>) -> Self {
let mut r = [T::zero(); B];
for b in 0..B {
r[b] = T::cst(c.0[b]);
}
Fl(r)
}
#[inline(always)]
pub fn muls(self, s: DD) -> Self {
let sv = DV::splat(s);
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b].mulc(sv);
}
Fl(r)
}
#[inline(always)]
pub fn mulf(self, s: f64) -> Self {
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b].mulf(s);
}
Fl(r)
}
#[inline(always)]
pub fn mul_pwr2(self, s: f64) -> Self {
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b].mul_pwr2(s);
}
Fl(r)
}
#[inline(always)]
pub fn mul_t(self, s: T) -> Self {
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b] * s;
}
Fl(r)
}
#[inline(always)]
pub fn adds(self, s: DD) -> Self {
let sv = DV::splat(s);
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b].addc(sv);
}
Fl(r)
}
pub fn val(&self) -> Fl<Dv<T>, B> {
let mut r = [DV::zero(); B];
for b in 0..B {
r[b] = self.0[b].val();
}
Fl(r)
}
pub fn mulp(self, p: T::P) -> Self {
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b].mulp(p);
}
Fl(r)
}
pub fn addp(self, p: T::P) -> Self {
let mut r = self.0;
for b in 0..B {
r[b] = self.0[b].addp(p);
}
Fl(r)
}
pub fn coef(&self, k: usize) -> Fl<Dv<T>, B> {
let mut r = [DV::zero(); B];
for b in 0..B {
r[b] = self.0[b].coef(k);
}
Fl(r)
}
pub fn set_coef(&mut self, k: usize, c: &Fl<Dv<T>, B>) {
for b in 0..B {
self.0[b].set_coef(k, c.0[b]);
}
}
pub fn coef_qd(&self, k: usize) -> Fl<QV<T::S>, B> {
let mut r = [QV::zero(); B];
for b in 0..B {
r[b] = self.0[b].coef_qd(k);
}
Fl(r)
}
pub fn set_coef_qd(&mut self, k: usize, c: &Fl<QV<T::S>, B>) {
for b in 0..B {
self.0[b].set_coef_qd(k, c.0[b]);
}
}
pub fn tan(&self) -> Fl<Dv<T>, B> {
let mut r = [DV::zero(); B];
for b in 0..B {
r[b] = self.0[b].tan();
}
Fl(r)
}
pub fn from_vt(v: &Fl<Dv<T>, B>, t: &Fl<Dv<T>, B>) -> Self {
let mut r = [T::zero(); B];
for b in 0..B {
r[b] = T::from_vt(v.0[b], t.0[b]);
}
Fl(r)
}
pub fn tan64(&self, k: usize) -> Fl<F8<T::S>, B> {
let mut r = [F8(V8::zero()); B];
for b in 0..B {
r[b] = F8(self.0[b].tan64(k));
}
Fl(r)
}
pub fn set_tan64(&mut self, k: usize, t: &Fl<F8<T::S>, B>) {
assert!(
T::TAN_F64 && k < T::NT,
"Fl::set_tan64: f64 tangent {k} of a lane type with {} f64 tangents",
T::NT
);
for b in 0..B {
self.0[b].set_tan64(k, t.0[b].0);
}
}
pub fn unit(j: usize) -> Self {
assert!(j < 8 * B, "Fl::unit: value {j} of a field of {} values", 8 * B);
let mut e = [0.0; 8];
e[j % 8] = 1.0;
let mut r = Self::zero();
r.0[j / 8] = T::cst(DV {
hi: V8::from_array(e),
lo: V8::zero(),
});
r
}
pub fn unit_tangent(v: &Fl<Dv<T>, B>, j: usize) -> Self {
assert!(T::TANGENT, "Fl::unit_tangent: a lane type without a tangent");
Self::from_vt(v, &Fl::<Dv<T>, B>::unit(j))
}
}
impl<S: Simd, const B: usize> Fl<Dc<S>, B> {
pub fn tan_re(&self) -> Fl<DV<S>, B> {
let mut r = [DV::zero(); B];
for b in 0..B {
r[b] = self.0[b].r;
}
Fl(r)
}
pub fn tan_im(&self) -> Fl<DV<S>, B> {
let mut r = [DV::zero(); B];
for b in 0..B {
r[b] = self.0[b].i;
}
Fl(r)
}
pub fn from_vri(v: &Fl<DV<S>, B>, re: &Fl<DV<S>, B>, im: &Fl<DV<S>, B>) -> Self {
let mut r = [Dc::zero(); B];
for b in 0..B {
r[b] = Dc {
v: v.0[b],
r: re.0[b],
i: im.0[b],
};
}
Fl(r)
}
}
impl<S: Simd, const B: usize> Fl<Qu<S>, B> {
pub fn from_vt_qd(v: &Fl<QV<S>, B>, t: &Fl<QV<S>, B>) -> Self {
let mut r = [Qu::zero(); B];
for b in 0..B {
r[b] = Qu { v: v.0[b], d: t.0[b] };
}
Fl(r)
}
}
impl<S: Simd, const B: usize> Fl<DV<S>, B> {
pub fn load(hi: &[f64], lo: &[f64]) -> Self {
let mut r = [DV::zero(); B];
for b in 0..B {
r[b] = DV::load(&hi[8 * b..8 * b + 8], &lo[8 * b..8 * b + 8]);
}
Fl(r)
}
pub fn store(&self, hi: &mut [f64], lo: &mut [f64]) {
for b in 0..B {
self.0[b].store(&mut hi[8 * b..8 * b + 8], &mut lo[8 * b..8 * b + 8]);
}
}
pub fn get(&self, j: usize) -> DD {
self.0[j / 8].lane(j % 8)
}
pub fn amax(&self) -> f64 {
let mut m = 0.0f64;
for b in 0..B {
m = m.max(self.0[b].hi.abs().hmax());
}
m
}
}
impl<S: Simd, const B: usize> Fl<QV<S>, B> {
pub fn load_parts(c0: &[f64], c1: &[f64], c2: &[f64], c3: &[f64]) -> Self {
let mut r = [QV::zero(); B];
for b in 0..B {
let o = 8 * b;
r[b] = QV::load(&c0[o..o + 8], &c1[o..o + 8], &c2[o..o + 8], &c3[o..o + 8]);
}
Fl(r)
}
pub fn store_parts(&self, c0: &mut [f64], c1: &mut [f64], c2: &mut [f64], c3: &mut [f64]) {
for b in 0..B {
let o = 8 * b;
self.0[b].store(
&mut c0[o..o + 8],
&mut c1[o..o + 8],
&mut c2[o..o + 8],
&mut c3[o..o + 8],
);
}
}
pub fn get(&self, j: usize) -> QD {
self.0[j / 8].lane(j % 8)
}
}
#[inline(always)]
pub fn cs<T: Lane, const B: usize>(x: &[Fl<T, B>], y: &[Fl<T, B>], k: usize) -> Fl<T, B> {
if T::VAL_F64 || T::TAN_F64 {
return cs_il(x, y, k, 0, k, |_| 1.0, false);
}
let mut out = [T::zero(); B];
for b in 0..B {
let mut a = T::acc0();
for j in 0..=k {
a = T::acc(a, x[j].0[b], y[k - j].0[b]);
}
out[b] = T::fin(a);
}
Fl(out)
}
#[inline(always)]
pub fn cs_range<T: Lane, const B: usize>(x: &[Fl<T, B>], y: &[Fl<T, B>], k: usize, lo: usize, hi: usize) -> Fl<T, B> {
if T::VAL_F64 || T::TAN_F64 {
return cs_il(x, y, k, lo, hi, |_| 1.0, false);
}
let mut out = [T::zero(); B];
for b in 0..B {
let mut a = T::acc0();
for j in lo..=hi {
a = T::acc(a, x[j].0[b], y[k - j].0[b]);
}
out[b] = T::fin(a);
}
Fl(out)
}
#[inline(always)]
pub fn cs_w<T: Lane, const B: usize>(
x: &[Fl<T, B>],
y: &[Fl<T, B>],
k: usize,
lo: usize,
hi: usize,
w: impl Fn(usize) -> f64,
) -> Fl<T, B> {
if T::VAL_F64 || T::TAN_F64 {
return cs_il(x, y, k, lo, hi, w, true);
}
let mut out = [T::zero(); B];
for b in 0..B {
let mut a = T::acc0();
for j in lo..=hi {
a = T::acc(a, x[j].0[b].mulf(w(j)), y[k - j].0[b]);
}
out[b] = T::fin(a);
}
Fl(out)
}
#[inline(always)]
fn cs_il<T: Lane, const B: usize>(
x: &[Fl<T, B>],
y: &[Fl<T, B>],
k: usize,
lo: usize,
hi: usize,
w: impl Fn(usize) -> f64,
weighted: bool,
) -> Fl<T, B> {
let mut a = [T::acc0(); B];
for j in lo..=hi {
let (xj, yj) = (&x[j].0, &y[k - j].0);
if weighted {
let wj = w(j);
for b in 0..B {
a[b] = T::acc(a[b], xj[b].mulf(wj), yj[b]);
}
} else {
for b in 0..B {
a[b] = T::acc(a[b], xj[b], yj[b]);
}
}
}
Fl(a.map(T::fin))
}
#[inline(always)]
pub fn cs_into<T: Lane, const B: usize>(out: &mut Fl<T, B>, x: &[Fl<T, B>], y: &[Fl<T, B>], k: usize) {
cs_range_into(out, x, y, k, 0, k);
}
#[inline(always)]
pub fn cs_range_into<T: Lane, const B: usize>(
out: &mut Fl<T, B>,
x: &[Fl<T, B>],
y: &[Fl<T, B>],
k: usize,
lo: usize,
hi: usize,
) {
if T::VAL_F64 || T::TAN_F64 {
cs_il_into(out, x, y, k, lo, hi, |_| 1.0, false);
} else {
for b in 0..B {
cs_lane_into(&mut out.0[b], b, x, y, k, lo, hi);
}
}
}
#[inline(always)]
pub fn cs_w_into<T: Lane, const B: usize>(
out: &mut Fl<T, B>,
x: &[Fl<T, B>],
y: &[Fl<T, B>],
k: usize,
lo: usize,
hi: usize,
w: impl Fn(usize) -> f64,
) {
if T::VAL_F64 || T::TAN_F64 {
cs_il_into(out, x, y, k, lo, hi, w, true);
} else {
for b in 0..B {
cs_w_lane_into(&mut out.0[b], b, x, y, k, lo, hi, &w);
}
}
}
#[inline(always)]
pub fn cs_lane_into<T: Lane, const B: usize>(
out: &mut T,
b: usize,
x: &[Fl<T, B>],
y: &[Fl<T, B>],
k: usize,
lo: usize,
hi: usize,
) {
let mut a = T::acc0();
for j in lo..=hi {
T::acc_mut(&mut a, &x[j].0[b], &y[k - j].0[b]);
}
*out = T::fin(a);
}
#[allow(clippy::too_many_arguments)]
#[inline(always)]
pub fn cs_w_lane_into<T: Lane, const B: usize>(
out: &mut T,
b: usize,
x: &[Fl<T, B>],
y: &[Fl<T, B>],
k: usize,
lo: usize,
hi: usize,
w: impl Fn(usize) -> f64,
) {
let mut a = T::acc0();
for j in lo..=hi {
let xw = x[j].0[b].mulf(w(j));
T::acc_mut(&mut a, &xw, &y[k - j].0[b]);
}
*out = T::fin(a);
}
#[allow(clippy::too_many_arguments)]
#[inline(always)]
fn cs_il_into<T: Lane, const B: usize>(
out: &mut Fl<T, B>,
x: &[Fl<T, B>],
y: &[Fl<T, B>],
k: usize,
lo: usize,
hi: usize,
w: impl Fn(usize) -> f64,
weighted: bool,
) {
let mut a = [T::acc0(); B];
for j in lo..=hi {
let (xj, yj) = (&x[j].0, &y[k - j].0);
if weighted {
let wj = w(j);
for b in 0..B {
let xw = xj[b].mulf(wj);
T::acc_mut(&mut a[b], &xw, &yj[b]);
}
} else {
for b in 0..B {
T::acc_mut(&mut a[b], &xj[b], &yj[b]);
}
}
}
for b in 0..B {
out.0[b] = T::fin(a[b]);
}
}
#[inline(always)]
pub fn horner<T: Lane, const B: usize>(s: &[Fl<T, B>], h: DD) -> Fl<T, B> {
let mut out = Fl::<T, B>::zero();
for k in (0..s.len()).rev() {
out = out.muls(h) + s[k];
}
out
}
#[derive(Clone)]
pub struct DMat<S: Simd, const B: usize> {
pub cols: Vec<Fl<DV<S>, B>>,
pub cols64: Vec<[V8<S>; B]>,
}
impl<S: Simd, const B: usize> DMat<S, B> {
pub fn from_rows(hi: &[f64], lo: &[f64]) -> Self {
let m = 8 * B;
let mut cols = Vec::with_capacity(m);
for j in 0..m {
let ch: Vec<f64> = (0..m).map(|i| hi[i * m + j]).collect();
let cl: Vec<f64> = (0..m).map(|i| lo[i * m + j]).collect();
cols.push(Fl::<DV<S>, B>::load(&ch, &cl));
}
let cols64 = cols.iter().map(|c| c.0.map(|v| v.hi)).collect();
DMat { cols, cols64 }
}
#[inline(always)]
pub fn apply<T: MatLane<S = S>>(&self, f: &Fl<T, B>) -> Fl<T, B> {
T::dmat_apply(self, f)
}
#[inline(always)]
pub fn apply_dd<T: Lane<S = S>>(&self, f: &Fl<T, B>) -> Fl<T, B> {
let mut acc = [T::acc0(); B];
for jb in 0..B {
for jl in 0..8 {
let s = f.0[jb].bcast(jl);
let col = &self.cols[8 * jb + jl];
for b in 0..B {
acc[b] = T::accc(acc[b], s, col.0[b]);
}
}
}
let mut out = [T::zero(); B];
for b in 0..B {
out[b] = T::fin(acc[b]);
}
Fl(out)
}
}
pub trait MatLane: Lane {
#[inline(always)]
fn dmat_apply<const B: usize>(d: &DMat<Self::S, B>, f: &Fl<Self, B>) -> Fl<Self, B> {
d.apply_dd(f)
}
}
impl<S: Simd> MatLane for DV<S> {}
impl<S: Simd> MatLane for Du<S> {}
impl<S: Simd> MatLane for Dc<S> {}
impl<S: Simd> MatLane for QV<S> {}
impl<S: Simd> MatLane for crate::ov::OV<S> {}
impl<S: Simd> MatLane for Qu<S> {}
impl<S: Simd, const N: usize> MatLane for Jet<S, N> {}
impl<S: Simd, const N: usize> MatLane for QJet<S, N> {}
impl<S: Simd> MatLane for F8<S> {
#[inline(always)]
fn dmat_apply<const B: usize>(d: &DMat<S, B>, f: &Fl<Self, B>) -> Fl<Self, B> {
let mut acc = [V8::zero(); B];
for jb in 0..B {
for jl in 0..8 {
let s = f.0[jb].0.bcast(jl);
let col = &d.cols64[8 * jb + jl];
for b in 0..B {
acc[b] = s.fma(col[b], acc[b]);
}
}
}
Fl(acc.map(F8))
}
}
impl<S: Simd> MatLane for Fu<S> {
#[inline(always)]
fn dmat_apply<const B: usize>(d: &DMat<S, B>, f: &Fl<Self, B>) -> Fl<Self, B> {
let mut av = [V8::zero(); B];
let mut ad = [V8::zero(); B];
for jb in 0..B {
for jl in 0..8 {
let sv = f.0[jb].v.bcast(jl);
let sd = f.0[jb].d.bcast(jl);
let col = &d.cols64[8 * jb + jl];
for b in 0..B {
av[b] = sv.fma(col[b], av[b]);
ad[b] = sd.fma(col[b], ad[b]);
}
}
}
let mut out = [Fu::zero(); B];
for b in 0..B {
out[b] = Fu { v: av[b], d: ad[b] };
}
Fl(out)
}
}
impl<S: Simd, const N: usize> MatLane for Dtn<S, N> {
#[inline(always)]
fn dmat_apply<const B: usize>(dm: &DMat<S, B>, f: &Fl<Self, B>) -> Fl<Self, B> {
let mut av = [DotAcc::zero(); B];
let mut ad = [[V8::zero(); N]; B];
for jb in 0..B {
for jl in 0..8 {
let sv = f.0[jb].v.bcast(jl);
let sd = f.0[jb].d.map(|x| x.bcast(jl));
let col = &dm.cols[8 * jb + jl];
let col64 = &dm.cols64[8 * jb + jl];
for b in 0..B {
av[b] = av[b].add_prod(sv, col.0[b]);
for i in 0..N {
ad[b][i] = sd[i].fma(col64[b], ad[b][i]);
}
}
}
}
let mut out = [Self::zero(); B];
for b in 0..B {
out[b] = Dtn {
v: av[b].finish(),
d: ad[b],
};
}
Fl(out)
}
}
impl<S: Simd, const N: usize> MatLane for Fun<S, N> {
#[inline(always)]
fn dmat_apply<const B: usize>(dm: &DMat<S, B>, f: &Fl<Self, B>) -> Fl<Self, B> {
let mut av = [V8::zero(); B];
let mut ad = [[V8::zero(); N]; B];
for jb in 0..B {
for jl in 0..8 {
let sv = f.0[jb].v.bcast(jl);
let sd = f.0[jb].d.map(|x| x.bcast(jl));
let col64 = &dm.cols64[8 * jb + jl];
for b in 0..B {
av[b] = sv.fma(col64[b], av[b]);
for i in 0..N {
ad[b][i] = sd[i].fma(col64[b], ad[b][i]);
}
}
}
}
let mut out = [Self::zero(); B];
for b in 0..B {
out[b] = Fun { v: av[b], d: ad[b] };
}
Fl(out)
}
}
impl<L: MatLane> MatLane for Counted<L> {
#[inline(always)]
fn dmat_apply<const B: usize>(d: &DMat<Self::S, B>, f: &Fl<Self, B>) -> Fl<Self, B> {
crate::dual::count_n(crate::dual::op::ACCC, (8 * B * B) as u64);
crate::dual::count_n(crate::dual::op::FIN, B as u64);
Fl(L::dmat_apply(d, &Fl(f.0.map(|x| x.0))).0.map(Counted))
}
}
pub trait FieldSolve {
fn solve_lanes<S: Simd, const B: usize>(&self, f: &Fl<DV<S>, B>) -> Fl<DV<S>, B>;
fn solve_lanes_hi<S: Simd, const B: usize>(&self, f: &Fl<DV<S>, B>) -> Fl<DV<S>, B>;
fn solve_lanes_refine<T: Lane, const B: usize>(
&self,
rhs: &Fl<T, B>,
steps: usize,
resid: impl FnMut(&Fl<T, B>) -> Fl<T, B>,
) -> Fl<T, B>;
fn solve_lanes_refine_t<T: Lane, const B: usize>(
&self,
lu_t: &Self,
rhs: &Fl<T, B>,
steps: usize,
resid: impl FnMut(&Fl<T, B>) -> Fl<T, B>,
) -> Fl<T, B>
where
Self: Sized;
fn solve_lanes_jet<T: Lane, const B: usize>(
&self,
rhs: &Fl<T, B>,
couple: impl FnMut(usize, &Fl<DV<T::S>, B>, Fl<DV<T::S>, B>) -> Fl<DV<T::S>, B>,
) -> Fl<T, B>;
fn solve_lanes_jet_refine<T: Lane, const B: usize>(
&self,
rhs: &Fl<T, B>,
steps: usize,
couple: impl FnMut(usize, &Fl<QV<T::S>, B>, Fl<QV<T::S>, B>) -> Fl<QV<T::S>, B>,
resid0: impl FnMut(&Fl<QV<T::S>, B>, &Fl<QV<T::S>, B>) -> Fl<QV<T::S>, B>,
) -> Fl<T, B>;
}
impl FieldSolve for DDLu {
fn solve_lanes<S: Simd, const B: usize>(&self, f: &Fl<DV<S>, B>) -> Fl<DV<S>, B> {
let m = 8 * B;
assert_eq!(
self.n, m,
"FieldSolve: a DDLu of order {} for a field of {m} values",
self.n
);
let mut h = vec![0.0; m];
let mut l = vec![0.0; m];
f.store(&mut h, &mut l);
let mut b: Vec<DD> = (0..m).map(|i| DD { hi: h[i], lo: l[i] }).collect();
self.solve(&mut b);
for i in 0..m {
h[i] = b[i].hi;
l[i] = b[i].lo;
}
Fl::<DV<S>, B>::load(&h, &l)
}
fn solve_lanes_hi<S: Simd, const B: usize>(&self, f: &Fl<DV<S>, B>) -> Fl<DV<S>, B> {
let m = 8 * B;
assert_eq!(
self.n, m,
"FieldSolve: a DDLu of order {} for a field of {m} values",
self.n
);
let mut h = vec![0.0; m];
let mut l = vec![0.0; m];
f.store(&mut h, &mut l);
self.solve_hi(&mut h);
l.iter_mut().for_each(|v| *v = 0.0);
Fl::<DV<S>, B>::load(&h, &l)
}
fn solve_lanes_refine<T: Lane, const B: usize>(
&self,
rhs: &Fl<T, B>,
steps: usize,
mut resid: impl FnMut(&Fl<T, B>) -> Fl<T, B>,
) -> Fl<T, B> {
assert!(
!T::TANGENT,
"FieldSolve::solve_lanes_refine refines values only: a lane type with tangents would lose them"
);
let z = Fl::<Dv<T>, B>::zero();
let mut x = Fl::<T, B>::from_vt(&self.solve_lanes(&rhs.val()), &z);
for _ in 0..steps {
let r = resid(&x);
x = x + Fl::<T, B>::from_vt(&self.solve_lanes(&r.val()), &z);
}
x
}
fn solve_lanes_refine_t<T: Lane, const B: usize>(
&self,
lu_t: &Self,
rhs: &Fl<T, B>,
steps: usize,
mut resid: impl FnMut(&Fl<T, B>) -> Fl<T, B>,
) -> Fl<T, B> {
assert!(
T::NJ == 0,
"FieldSolve::solve_lanes_refine_t refines one tangent: a jet would lose its orders past 1 (solve_lanes_jet)"
);
let z = Fl::<Dv<T>, B>::zero();
let tsolve = |r: &Fl<T, B>| if T::TANGENT { lu_t.solve_lanes(&r.tan()) } else { z };
let mut x = Fl::<T, B>::from_vt(&self.solve_lanes(&rhs.val()), &tsolve(rhs));
for _ in 0..steps {
let r = resid(&x);
x = x + Fl::<T, B>::from_vt(&self.solve_lanes(&r.val()), &tsolve(&r));
}
x
}
fn solve_lanes_jet<T: Lane, const B: usize>(
&self,
rhs: &Fl<T, B>,
mut couple: impl FnMut(usize, &Fl<DV<T::S>, B>, Fl<DV<T::S>, B>) -> Fl<DV<T::S>, B>,
) -> Fl<T, B> {
assert!(
T::NJ > 0,
"FieldSolve::solve_lanes_jet solves jets: a lane type without jet coefficients has no orders"
);
let mut x = Fl::<T, B>::zero();
let mut xs: Vec<Fl<DV<T::S>, B>> = Vec::with_capacity(T::NJ);
for k in 0..T::NJ {
let mut r = rhs.coef(k);
for j in 1..=k {
r = couple(j, &xs[k - j], r);
}
let xk = self.solve_lanes(&r);
x.set_coef(k, &xk);
xs.push(xk);
}
x
}
fn solve_lanes_jet_refine<T: Lane, const B: usize>(
&self,
rhs: &Fl<T, B>,
steps: usize,
mut couple: impl FnMut(usize, &Fl<QV<T::S>, B>, Fl<QV<T::S>, B>) -> Fl<QV<T::S>, B>,
mut resid0: impl FnMut(&Fl<QV<T::S>, B>, &Fl<QV<T::S>, B>) -> Fl<QV<T::S>, B>,
) -> Fl<T, B> {
assert!(
T::NJ > 0,
"FieldSolve::solve_lanes_jet_refine solves jets: a lane type without jet coefficients has no orders"
);
let mut x = Fl::<T, B>::zero();
let mut xs: Vec<Fl<QV<T::S>, B>> = Vec::with_capacity(T::NJ);
for k in 0..T::NJ {
let mut r = rhs.coef_qd(k);
for j in 1..=k {
r = couple(j, &xs[k - j], r);
}
let xk = self.solve_lanes_refine(&r, steps, |y| resid0(&r, y));
x.set_coef_qd(k, &xk);
xs.push(xk);
}
x
}
}
pub struct TangentTail {
rk: f64,
r: f64,
big: f64,
run: usize,
tol: f64,
run_len: usize,
kmin: usize,
}
impl TangentTail {
pub fn new(r: f64, tol: f64, run: usize, kmin: usize) -> Self {
TangentTail {
rk: 1.0,
r,
big: 0.0,
run: 0,
tol,
run_len: run,
kmin,
}
}
pub fn done<T: Lane, const B: usize>(&mut self, k: usize, f: &[&Fl<T, B>]) -> bool {
let mut a = 0.0f64;
for x in f {
for b in 0..B {
if T::TAN_F64 {
for t in 0..T::NT {
a = a.max(x.0[b].tan64(t).abs().hmax());
}
} else {
a = a.max(x.0[b].tan().hi.abs().hmax());
}
}
}
let t = a * self.rk;
self.rk *= self.r;
self.big = self.big.max(t);
self.run = if t <= self.tol * self.big { self.run + 1 } else { 0 };
self.big > 0.0 && k >= self.kmin && self.run >= self.run_len
}
}