use super::{Detect, Loc};
use crate::state::{State, StateFnMut};
pub trait Locate<const N: usize> {
fn locate(&mut self, state: &impl State<N>) -> Option<f64>;
}
pub struct StepBegin;
pub struct StepEnd;
pub struct StepHalf;
pub struct Lerp;
pub struct Bisection;
pub struct BisectionBool;
pub struct RegulaFalsi;
impl<const N: usize, F, D> Locate<N> for Loc<F, D, StepBegin>
where
Self: Detect<N>,
{
fn locate(&mut self, state: &impl State<N>) -> Option<f64> {
self.detect(state).then_some(state.t_prev())
}
}
impl<const N: usize, F, D> Locate<N> for Loc<F, D, StepEnd>
where
Self: Detect<N>,
{
fn locate(&mut self, state: &impl State<N>) -> Option<f64> {
self.detect(state).then_some(state.t())
}
}
impl<const N: usize, F, D> Locate<N> for Loc<F, D, StepHalf>
where
Self: Detect<N>,
{
fn locate(&mut self, state: &impl State<N>) -> Option<f64> {
self.detect(state)
.then(|| 0.5 * (state.t_prev() + state.t()))
}
}
impl<const N: usize, F: StateFnMut<N, Output = f64>, D> Locate<N> for Loc<F, D, Lerp>
where
Self: Detect<N>,
{
fn locate(&mut self, state: &impl State<N>) -> Option<f64> {
self.detect(state).then(|| {
let curr = self.0.eval(state);
let prev = self.0.eval_prev(state);
(curr * state.t_prev() - prev * state.t()) / (curr - prev)
})
}
}
impl<const N: usize, F: StateFnMut<N, Output = bool>, D> Locate<N> for Loc<F, D, BisectionBool>
where
Self: Detect<N>,
{
fn locate(&mut self, state: &impl State<N>) -> Option<f64> {
self.detect(state).then(|| {
let mut l = state.t_prev();
let mut r = state.t();
if self.0.eval_prev(state) {
std::mem::swap(&mut l, &mut r);
}
for _ in 0..f64::MANTISSA_DIGITS {
let m = 0.5 * (l + r);
match self.0.eval_at(state, m) {
false => l = m,
true => r = m,
}
}
f64::max(l, r)
})
}
}
impl<const N: usize, F: StateFnMut<N, Output = f64>, D> Locate<N> for Loc<F, D, RegulaFalsi>
where
Self: Detect<N>,
{
fn locate(&mut self, state: &impl State<N>) -> Option<f64> {
self.detect(state).then(|| {
let mut l = state.t_prev();
let mut r = state.t();
if self.0.eval(state) < 0. {
std::mem::swap(&mut l, &mut r);
}
let mut m = 0.;
for _ in 0..f64::MANTISSA_DIGITS {
let f_l = self.0.eval_at(state, l);
let f_r = self.0.eval_at(state, r);
m = (f_r * l - f_l * r) / (f_r - f_l);
let f_m = self.0.eval_at(state, m);
match f_m < 0. {
true => {
l = m;
}
false => {
r = m;
}
}
if f_m.abs() < f64::EPSILON {
break;
}
}
m
})
}
}
impl<const N: usize, F: StateFnMut<N, Output = f64>, D> Locate<N> for Loc<F, D, Bisection>
where
Self: Detect<N>,
{
fn locate(&mut self, state: &impl State<N>) -> Option<f64> {
self.detect(state).then(|| {
let mut l = state.t_prev();
let mut r = state.t();
if self.0.eval(state) < 0. {
std::mem::swap(&mut l, &mut r);
}
for _ in 0..f64::MANTISSA_DIGITS {
let m = 0.5 * (l + r);
match self.0.eval_at(state, m) < 0. {
true => l = m,
false => r = m,
}
}
f64::max(l, r)
})
}
}