1use crate::Residual;
3use nalgebra::{Const, DefaultAllocator, Dim, U1, allocator::Allocator};
4use num_dual::{Derivative, DualNum, DualSVec};
5
6#[cfg(feature = "ndarray")]
7mod dataset;
8mod properties;
9#[cfg(feature = "ndarray")]
10pub use dataset::*;
11pub use properties::*;
12
13pub(crate) type Gradient<const P: usize> = DualSVec<f64, f64, P>;
14
15pub trait ParametersAD<N: Dim>: Residual<N>
17where
18 DefaultAllocator: Allocator<N>,
19{
20 fn build<D: DualNum<f64, Inner = f64> + Copy>(
27 f: impl FnMut(&'static str, bool) -> D,
28 ) -> Self::Lifted<D>;
29
30 fn parameter_names() -> Vec<&'static str> {
32 let mut names = Vec::new();
33 let _ = Self::build(|name, _| {
34 names.push(name);
35 0.0
36 });
37 names
38 }
39
40 fn differentiable_parameters() -> Vec<&'static str> {
42 let mut names = Vec::new();
43 let _ = Self::build(|name, differentiable| {
44 if differentiable {
45 names.push(name);
46 }
47 0.0
48 });
49 names
50 }
51
52 fn seed_derivatives<const P: usize>(
60 parameter_values: &[f64],
61 derivative_names: [&str; P],
62 ) -> Self::Lifted<Gradient<P>> {
63 let mut idx = 0;
64 Self::build(|name, _differentiable| {
65 let i = idx;
66 idx += 1;
67 let mut d = Gradient::<P>::from(parameter_values[i]);
68 if let Some(seed_idx) = derivative_names.iter().position(|&n| n == name) {
69 d.eps =
70 Derivative::<_, _, Const<P>, _>::derivative_generic(Const::<P>, U1, seed_idx);
71 }
72 d
73 })
74 }
75}