use crate::Result;
use crate::data::validate_matrix_len;
use crate::workspace::validate_output;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FitReport {
pub iterations: usize,
pub converged: bool,
pub tolerance: f64,
}
impl FitReport {
#[must_use]
pub fn new(iterations: usize, converged: bool, tolerance: f64) -> Self {
Self {
iterations,
converged,
tolerance,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Fit1D {
pub baseline: Vec<f64>,
pub report: FitReport,
}
impl Fit1D {
pub fn corrected(&self, y: &[f64]) -> Result<Vec<f64>> {
validate_output("y", self.baseline.len(), y.len())?;
Ok(y.iter()
.zip(&self.baseline)
.map(|(observed, baseline)| observed - baseline)
.collect())
}
pub fn corrected_into(&self, y: &[f64], output: &mut [f64]) -> Result<()> {
validate_output("y", self.baseline.len(), y.len())?;
validate_output("output", self.baseline.len(), output.len())?;
for ((target, observed), baseline) in output.iter_mut().zip(y).zip(&self.baseline) {
*target = observed - baseline;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FitHistory {
pub baseline: Vec<f64>,
pub report: FitReport,
pub tol_history: Vec<f64>,
}
impl FitHistory {
pub fn corrected(&self, y: &[f64]) -> Result<Vec<f64>> {
validate_output("y", self.baseline.len(), y.len())?;
Ok(y.iter()
.zip(&self.baseline)
.map(|(observed, baseline)| observed - baseline)
.collect())
}
pub fn corrected_into(&self, y: &[f64], output: &mut [f64]) -> Result<()> {
validate_output("y", self.baseline.len(), y.len())?;
validate_output("output", self.baseline.len(), output.len())?;
for ((target, observed), baseline) in output.iter_mut().zip(y).zip(&self.baseline) {
*target = observed - baseline;
}
Ok(())
}
#[must_use]
pub fn into_fit(self) -> Fit1D {
Fit1D {
baseline: self.baseline,
report: self.report,
}
}
}
pub type Fit = Fit1D;
#[derive(Debug, Clone, PartialEq)]
pub struct Fit2D {
pub baseline: Vec<f64>,
pub rows: usize,
pub cols: usize,
pub report: FitReport,
}
impl Fit2D {
pub fn new(baseline: Vec<f64>, rows: usize, cols: usize, report: FitReport) -> Result<Self> {
validate_matrix_len("baseline", rows, cols, baseline.len())?;
Ok(Self {
baseline,
rows,
cols,
report,
})
}
#[must_use]
pub fn len(&self) -> usize {
self.baseline.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.baseline.is_empty()
}
#[must_use]
pub fn shape(&self) -> (usize, usize) {
(self.rows, self.cols)
}
pub fn corrected(&self, data: &[f64]) -> Result<Vec<f64>> {
validate_output("data", self.baseline.len(), data.len())?;
Ok(data
.iter()
.zip(&self.baseline)
.map(|(observed, baseline)| observed - baseline)
.collect())
}
pub fn corrected_into(&self, data: &[f64], output: &mut [f64]) -> Result<()> {
validate_output("data", self.baseline.len(), data.len())?;
validate_output("output", self.baseline.len(), output.len())?;
for ((target, observed), baseline) in output.iter_mut().zip(data).zip(&self.baseline) {
*target = observed - baseline;
}
Ok(())
}
}