nereids_fitting/forward_model.rs
1//! Solver-agnostic forward model trait.
2//!
3//! Unlike [`FitModel`](crate::lm::FitModel), which is LM-specific (evaluates
4//! residuals + Jacobian in chi-squared space), `ForwardModel` exposes the
5//! raw model prediction and parameter Jacobian. Each solver wraps this to
6//! compute its own objective and gradient:
7//!
8//! - **LM**: residuals = `(data - predict) / σ`, J_lm = `-jacobian / σ`
9//! - **KL**: gradient = `Σ (1 - data/predict) · jacobian`
10//!
11//! This makes new model extensions (background, temperature, etc.) work with
12//! both solvers automatically — implement `ForwardModel` once, both solvers
13//! benefit.
14
15use crate::error::FittingError;
16
17/// Solver-agnostic forward model.
18///
19/// Implementations provide the model prediction and (optionally) its
20/// analytical Jacobian. Solvers wrap this trait to compute solver-specific
21/// objectives (chi-squared, Poisson NLL, etc.).
22pub trait ForwardModel {
23 /// Predict model output for the given parameter vector.
24 ///
25 /// Returns a vector of predicted values (transmission, counts, etc.)
26 /// with length equal to the number of data points.
27 fn predict(&self, params: &[f64]) -> Result<Vec<f64>, FittingError>;
28
29 /// Analytical Jacobian (column-major layout).
30 ///
31 /// Returns a `Vec` of column vectors: `result[j]` is the j-th column
32 /// (partial derivatives of all data points w.r.t. the j-th free
33 /// parameter), so `result[j][i] = ∂predict[i] / ∂params[free_param_indices[j]]`.
34 ///
35 /// Only the columns corresponding to `free_param_indices` are needed.
36 /// Returns `None` to signal "use finite differences" (the default).
37 ///
38 /// `y_current` is the output of `predict(params)`, provided so
39 /// implementations can avoid redundant computation.
40 fn jacobian(
41 &self,
42 _params: &[f64],
43 _free_param_indices: &[usize],
44 _y_current: &[f64],
45 ) -> Option<Vec<Vec<f64>>> {
46 None
47 }
48
49 /// Number of data points in the model output.
50 fn n_data(&self) -> usize;
51
52 /// Number of parameters (total, including fixed).
53 fn n_params(&self) -> usize;
54}