feos_core/ad/dataset/
mod.rs1mod binary;
2mod pure;
3
4use std::{io, path::Path, sync::Arc};
5
6use nalgebra::Const;
7use ndarray::{Array1, Array2, ArrayView1, ArrayView2};
8use serde::de::DeserializeOwned;
9
10use crate::Residual;
11use crate::ad::Gradient;
12
13use super::ParametersAD;
14
15pub use binary::*;
16pub use pure::*;
17
18struct DatasetData {
20 inputs: Array2<f64>,
21 target: Array1<f64>,
22}
23
24#[derive(Clone)]
26struct DatasetStorage {
27 data: Arc<DatasetData>,
28 name: Option<String>,
29}
30
31impl DatasetStorage {
32 fn from_records<R: DatasetRecord>(records: Vec<R>) -> Self {
33 let n = records.len();
34 let inputs = Array2::from_shape_fn((n, R::N_INPUTS), |(i, j)| records[i].input(j));
35 let target = Array1::from_iter(records.iter().map(DatasetRecord::target));
36 Self {
37 data: Arc::new(DatasetData { inputs, target }),
38 name: None,
39 }
40 }
41
42 fn from_csv<R: DatasetRecord>(path: &Path) -> Result<Self, csv::Error> {
43 let records = csv::Reader::from_path(path)?
44 .deserialize()
45 .collect::<Result<Vec<R>, _>>()?;
46 Ok(Self::from_records(records))
47 }
48
49 fn from_reader<R: DatasetRecord>(reader: impl io::Read) -> Result<Self, csv::Error> {
50 let records = csv::Reader::from_reader(reader)
51 .deserialize()
52 .collect::<Result<Vec<R>, _>>()?;
53 Ok(Self::from_records(records))
54 }
55
56 fn inputs(&self) -> ArrayView2<'_, f64> {
57 self.data.inputs.view()
58 }
59
60 fn target(&self) -> ArrayView1<'_, f64> {
61 self.data.target.view()
62 }
63
64 fn name(&self) -> Option<&str> {
65 self.name.as_deref()
66 }
67
68 fn set_name(&mut self, name: String) {
69 self.name = Some(name);
70 }
71}
72
73pub trait DatasetRecord: DeserializeOwned {
75 const N_INPUTS: usize;
77
78 fn input(&self, column: usize) -> f64;
80
81 fn target(&self) -> f64;
83}
84
85pub trait Dataset {
87 fn inputs(&self) -> ArrayView2<'_, f64>;
89
90 fn target(&self) -> ArrayView1<'_, f64>;
92
93 fn name(&self) -> &str;
97
98 fn input_names(&self) -> &'static [&'static str];
100
101 fn target_name(&self) -> &'static str;
103
104 fn evaluate<E: Residual + Sync>(&self, eos: &E) -> (Array1<f64>, Array1<bool>);
111}
112
113macro_rules! define_dataset_ad {
117 ($($p:literal),+ $(,)?) => {
118 pub const GRADIENT_SLOTS: &[usize] = &[$($p),+];
120
121 pub trait DatasetAD<const N: usize>: Dataset {
124 fn evaluate_ad_const<T: ParametersAD<Const<N>>, const P: usize>(
126 &self,
127 names: [String; P],
128 parameters: &[f64],
129 inputs: ArrayView2<f64>,
130 ) -> (Array1<f64>, Array2<f64>, Array1<bool>)
131 where
132 T::Lifted<Gradient<P>>: Sync;
133
134 fn evaluate_ad<T: ParametersAD<Const<N>>>(
141 &self,
142 param_names: &[String],
143 parameters: &[f64],
144 ) -> (Array1<f64>, Array2<f64>, Array1<bool>)
145 where
146 $(T::Lifted<Gradient<$p>>: Sync,)*
147 {
148 fn to_const<const P: usize>(names: &[String]) -> [String; P] {
149 names.to_vec().try_into().expect("parameter count mismatch")
150 }
151
152 match param_names.len() {
153 $(
154 $p => self.evaluate_ad_const::<T, $p>(
155 to_const(param_names),
156 parameters,
157 self.inputs().view(),
158 ),
159 )+
160 p => unreachable!(
161 "parameter count {p} is not a member of GRADIENT_SLOTS={:?}",
162 GRADIENT_SLOTS,
163 ),
164 }
165 }
166 }
167 };
168}
169
170define_dataset_ad!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);