use hlist2::{HList, Nil, ops::Append};
use crate::*;
pub struct Equation<
const N: usize,
RHS: StateFnMut<N, Output = [f64; N]>,
Propagations: HList = Nil,
Events: HList = Nil,
> {
pub rhs: RHS,
pub propagations: Propagations,
pub events: Events,
pub max_delay: f64,
}
#[macro_export]
macro_rules! equation {
(|| $expr:expr) => {
$crate::Equation::new($crate::state_fn!(|| $expr)).max_delay(0.)
};
(|$t:ident| $expr:expr) => {
$crate::Equation::new($crate::state_fn!(|$t| $expr)).max_delay(0.)
};
(|[$($x:pat),+]| $expr:expr) => {
$crate::Equation::new($crate::state_fn!(|[$($x),+]| $expr)).max_delay(0.)
};
(|$t:pat, [$($x:pat),+]| $expr:expr) => {
$crate::Equation::new($crate::state_fn!(|$t, [$($x),+]| $expr)).max_delay(0.)
};
(|$t:pat, [$($x:pat),+], [$($x_:pat),+]| $expr:expr) => {
$crate::Equation::new($crate::state_fn!(|$t, [$($x),+], [$($x_),+]| $expr)).max_delay(f64::MAX)
};
}
impl<const N: usize, RHS: StateFnMut<N, Output = [f64; N]>> Equation<N, RHS> {
pub fn new(rhs: RHS) -> Self {
Equation {
rhs,
max_delay: f64::NAN,
propagations: Nil,
events: Nil,
}
}
pub fn max_delay(self, value: f64) -> Self {
Self {
rhs: self.rhs,
max_delay: value,
propagations: Nil,
events: Nil,
}
}
}
impl<const N: usize, RHS: StateFnMut<N, Output = [f64; N]>, Propagations: HList, Events: HList>
Equation<N, RHS, Propagations, Events>
{
pub fn loc<L: Locate<N>>(
self,
locate: L,
) -> Equation<N, RHS, Propagations, <Events as Append>::Output<(L, impl EventCall<N>)>>
where
Events: Append,
{
let Equation {
rhs,
propagations,
events,
max_delay,
} = self;
Equation {
rhs,
propagations,
events: events.append((locate, event_mut!())),
max_delay,
}
}
pub fn on_loc<L: Locate<N>, E: EventCall<N>>(
self,
locate: L,
event: E,
) -> Equation<N, RHS, Propagations, <Events as Append>::Output<(L, E)>>
where
Events: Append,
{
let Equation {
rhs,
propagations,
events,
max_delay,
} = self;
Equation {
rhs,
propagations,
events: events.append((locate, event)),
max_delay,
}
}
pub fn delay_with_smoothing_order<D: StateFnMut<N, Output = f64>>(
self,
delayed_arg_fn: D,
smoothing_order: usize,
) -> Equation<
N,
RHS,
<Propagations as Append>::Output<Loc<Propagator<N, D>, Propagation, location::Bisection>>,
Events,
>
where
Propagations: Append,
{
let Equation {
rhs,
propagations,
events,
max_delay: _,
} = self;
Equation {
rhs,
propagations: propagations.append(crate::loc::Loc(
crate::loc::Propagator::new(delayed_arg_fn, smoothing_order),
crate::loc::Propagation,
crate::loc::location::Bisection,
)),
events,
max_delay: f64::INFINITY,
}
}
pub fn delay<D: StateFnMut<N, Output = f64>>(
self,
delayed_arg_fn: D,
) -> Equation<
N,
RHS,
<Propagations as Append>::Output<Loc<Propagator<N, D>, Propagation, location::Bisection>>,
Events,
>
where
Propagations: Append,
{
self.delay_with_smoothing_order(delayed_arg_fn, 1)
}
pub fn neutral_delay<D: StateFnMut<N, Output = f64>>(
self,
delayed_arg_fn: D,
) -> Equation<
N,
RHS,
<Propagations as Append>::Output<Loc<Propagator<N, D>, Propagation, location::Bisection>>,
Events,
>
where
Propagations: Append,
{
self.delay_with_smoothing_order(delayed_arg_fn, 0)
}
pub fn const_delay(
self,
delay: f64,
) -> Equation<
N,
RHS,
<Propagations as Append>::Output<
Loc<Propagator<N, impl StateFnMut<N, Output = f64>>, Propagation, location::Bisection>,
>,
Events,
>
where
Propagations: Append,
{
self.const_delay_with_smoothing_order(delay, 1)
}
pub fn const_neutral_delay(
self,
delay: f64,
) -> Equation<
N,
RHS,
<Propagations as Append>::Output<
Loc<Propagator<N, impl StateFnMut<N, Output = f64>>, Propagation, location::Bisection>,
>,
Events,
>
where
Propagations: Append,
{
self.const_delay_with_smoothing_order(delay, 0)
}
pub fn const_delay_with_smoothing_order(
self,
delay: f64,
smoothing_order: usize,
) -> Equation<
N,
RHS,
<Propagations as Append>::Output<
Loc<Propagator<N, impl StateFnMut<N, Output = f64>>, Propagation, location::Bisection>,
>,
Events,
>
where
Propagations: Append,
{
let Equation {
rhs,
propagations,
events,
mut max_delay,
} = self;
if max_delay.is_nan() {
max_delay = delay;
} else if !max_delay.is_infinite() {
max_delay = max_delay.max(delay)
}
Equation {
rhs,
propagations: propagations.append(crate::loc::Loc(
crate::loc::Propagator::new(state_fn!(move |t| t - delay), smoothing_order),
crate::loc::Propagation,
crate::loc::location::Bisection,
)),
events,
max_delay,
}
}
}