Skip to main content

rill_ml/
traits.rs

1//! Core traits shared across RillML.
2//!
3//! These traits are intentionally small and concrete. RillML avoids heavy
4//! trait-object based polymorphism in favor of concrete, serializable types
5//! for optimizers and losses.
6
7use crate::error::RillError;
8use crate::sparse::SparseFeatures;
9
10/// An online regressor that produces real-valued predictions.
11///
12/// Implementations must keep `predict` side-effect free: calling `predict`
13/// must never update internal state. State updates happen exclusively in
14/// [`learn`](Self::learn).
15pub trait OnlineRegressor {
16    /// The number of features the model expects.
17    fn feature_count(&self) -> usize;
18
19    /// How many training samples the model has seen so far.
20    fn samples_seen(&self) -> u64;
21
22    /// Predict the target for the given feature slice.
23    ///
24    /// This method must not modify the model. If the feature dimension does
25    /// not match [`feature_count`](Self::feature_count) or the values are
26    /// not finite, an error is returned.
27    fn predict(&self, features: &[f64]) -> Result<f64, RillError>;
28
29    /// Update the model using a single labeled sample.
30    fn learn(&mut self, features: &[f64], target: f64) -> Result<(), RillError>;
31
32    /// Reset the model to its initial state, as if no samples had been seen.
33    fn reset(&mut self);
34}
35
36/// An online binary classifier that produces a probability in `(0, 1)`.
37///
38/// `predict` (and `predict_proba`) must be side-effect free.
39pub trait OnlineBinaryClassifier {
40    /// The number of features the model expects.
41    fn feature_count(&self) -> usize;
42
43    /// How many training samples the model has seen so far.
44    fn samples_seen(&self) -> u64;
45
46    /// Predict the probability of the positive class.
47    fn predict_proba(&self, features: &[f64]) -> Result<f64, RillError>;
48
49    /// Predict the boolean class label using a 0.5 threshold.
50    fn predict(&self, features: &[f64]) -> Result<bool, RillError> {
51        Ok(self.predict_proba(features)? >= 0.5)
52    }
53
54    /// Update the model using a single labeled sample.
55    fn learn(&mut self, features: &[f64], target: bool) -> Result<(), RillError>;
56
57    /// Reset the model to its initial state.
58    fn reset(&mut self);
59}
60
61/// A stateful feature transformer.
62///
63/// The contract is:
64/// - [`transform`](Self::transform) is read-only and must not update state.
65/// - [`update`](Self::update) uses the raw features to refresh internal
66///   statistics. It must not read the target label.
67pub trait Transformer {
68    /// Expected number of input features.
69    fn input_dim(&self) -> usize;
70
71    /// Number of features produced by [`transform`](Self::transform).
72    fn output_dim(&self) -> usize;
73
74    /// Transform features using the current internal state.
75    fn transform(&self, features: &[f64]) -> Result<Vec<f64>, RillError>;
76
77    /// Update internal statistics using raw features.
78    fn update(&mut self, features: &[f64]) -> Result<(), RillError>;
79
80    /// How many samples the transformer has seen.
81    fn samples_seen(&self) -> u64;
82
83    /// Reset the transformer to its initial state.
84    fn reset(&mut self);
85}
86
87/// An online evaluation metric.
88///
89/// Metrics are updated sample-by-sample via [`update`](Self::update) and
90/// queried via [`value`](Self::value). When insufficient data has been
91/// observed, `value` returns `None` rather than a misleading zero.
92pub trait Metric {
93    /// The ground-truth type for this metric.
94    type Truth;
95
96    /// The prediction type for this metric.
97    type Prediction;
98
99    /// Incorporate a single observation.
100    fn update(&mut self, truth: Self::Truth, prediction: Self::Prediction)
101    -> Result<(), RillError>;
102
103    /// Current metric value, or `None` if not enough data has been seen.
104    fn value(&self) -> Option<f64>;
105
106    /// How many observations have been incorporated.
107    fn samples_seen(&self) -> u64;
108
109    /// Reset the metric.
110    fn reset(&mut self);
111}
112
113/// An online univariate statistic (mean, variance, etc.).
114///
115/// All implementations must use `O(1)` memory unless explicitly documented
116/// otherwise (e.g. rolling statistics).
117pub trait OnlineStatistic {
118    /// Update the statistic with a new observation.
119    ///
120    /// Returns an error if `value` is not finite, unless the implementation
121    /// explicitly opts in to a NaN-handling policy.
122    fn update(&mut self, value: f64) -> Result<(), RillError>;
123
124    /// How many observations have been incorporated.
125    fn samples_seen(&self) -> u64;
126
127    /// Reset the statistic.
128    fn reset(&mut self);
129}
130
131/// An online regressor that accepts sparse features.
132///
133/// Implementations must keep `predict` side-effect free.
134pub trait SparseRegressor {
135    /// How many training samples the model has seen so far.
136    fn samples_seen(&self) -> u64;
137
138    /// Predict the target for the given sparse features.
139    ///
140    /// This method must not modify the model.
141    fn predict(&self, features: &SparseFeatures) -> Result<f64, RillError>;
142
143    /// Update the model using a single labeled sparse sample.
144    fn learn(&mut self, features: &SparseFeatures, target: f64) -> Result<(), RillError>;
145
146    /// Reset the model to its initial state.
147    fn reset(&mut self);
148}
149
150/// An online binary classifier that accepts sparse features.
151///
152/// `predict` (and `predict_proba`) must be side-effect free.
153pub trait SparseClassifier {
154    /// How many training samples the model has seen so far.
155    fn samples_seen(&self) -> u64;
156
157    /// Predict the probability of the positive class.
158    fn predict_proba(&self, features: &SparseFeatures) -> Result<f64, RillError>;
159
160    /// Predict the boolean class label using a 0.5 threshold.
161    fn predict(&self, features: &SparseFeatures) -> Result<bool, RillError> {
162        Ok(self.predict_proba(features)? >= 0.5)
163    }
164
165    /// Update the model using a single labeled sparse sample.
166    fn learn(&mut self, features: &SparseFeatures, target: bool) -> Result<(), RillError>;
167
168    /// Reset the model to its initial state.
169    fn reset(&mut self);
170}