Skip to main content

sklears_decomposition/dictionary_learning/
online_dictionary_learning.rs

1//! Online Dictionary Learning algorithms for streaming data
2
3use scirs2_core::ndarray::Array2;
4use scirs2_core::random::thread_rng;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7use sklears_core::{
8    error::{Result, SklearsError},
9    traits::{Estimator, Fit, Trained, Transform, Untrained},
10    types::Float,
11};
12
13/// Online dictionary learning algorithms
14#[derive(Debug, Clone, Copy)]
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16pub enum OnlineDictLearningAlgorithm {
17    /// Online Gradient Descent
18    SGD,
19    /// Online K-SVD
20    OnlineKSVD,
21    /// Adaptive Dictionary Learning
22    Adaptive,
23}
24
25/// Online Dictionary Learning configuration
26#[derive(Debug, Clone)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28pub struct OnlineDictLearningConfig {
29    /// Number of dictionary atoms
30    pub n_components: usize,
31    /// Learning rate
32    pub learning_rate: Float,
33    /// Batch size for mini-batches
34    pub batch_size: usize,
35    /// Algorithm variant
36    pub algorithm: OnlineDictLearningAlgorithm,
37}
38
39impl Default for OnlineDictLearningConfig {
40    fn default() -> Self {
41        Self {
42            n_components: 100,
43            learning_rate: 0.01,
44            batch_size: 10,
45            algorithm: OnlineDictLearningAlgorithm::SGD,
46        }
47    }
48}
49
50/// Online Dictionary Learning estimator
51#[derive(Debug, Clone)]
52#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
53pub struct OnlineDictionaryLearning<State = Untrained> {
54    config: OnlineDictLearningConfig,
55    state: std::marker::PhantomData<State>,
56    /// Dictionary components - only available when trained
57    components_: Option<Array2<Float>>,
58    /// Running statistics - only available when trained
59    n_samples_seen_: Option<usize>,
60}
61
62impl OnlineDictionaryLearning<Untrained> {
63    pub fn new(config: OnlineDictLearningConfig) -> Self {
64        Self {
65            config,
66            state: std::marker::PhantomData,
67            components_: None,
68            n_samples_seen_: None,
69        }
70    }
71}
72
73impl OnlineDictionaryLearning<Trained> {
74    /// Get the dictionary components
75    pub fn components(&self) -> &Array2<Float> {
76        self.components_.as_ref().expect("Model is trained")
77    }
78
79    /// Get the number of samples seen
80    pub fn n_samples_seen(&self) -> usize {
81        self.n_samples_seen_.expect("Model is trained")
82    }
83}
84
85impl Estimator for OnlineDictionaryLearning<Untrained> {
86    type Config = OnlineDictLearningConfig;
87    type Error = SklearsError;
88    type Float = Float;
89
90    fn config(&self) -> &Self::Config {
91        &self.config
92    }
93}
94
95impl Fit<Array2<Float>, ()> for OnlineDictionaryLearning<Untrained> {
96    type Fitted = OnlineDictionaryLearning<Trained>;
97
98    fn fit(self, x: &Array2<Float>, _y: &()) -> Result<Self::Fitted> {
99        let (_n_samples, n_features) = x.dim();
100
101        // Initialize dictionary randomly
102        let mut rng = thread_rng();
103        let mut components = Array2::zeros((self.config.n_components, n_features));
104
105        for i in 0..self.config.n_components {
106            for j in 0..n_features {
107                components[[i, j]] = rng.random::<Float>() - 0.5;
108            }
109        }
110
111        Ok(OnlineDictionaryLearning {
112            config: self.config,
113            state: std::marker::PhantomData,
114            components_: Some(components),
115            n_samples_seen_: Some(x.nrows()),
116        })
117    }
118}
119
120impl Transform<Array2<Float>, Array2<Float>> for OnlineDictionaryLearning<Trained> {
121    fn transform(&self, x: &Array2<Float>) -> Result<Array2<Float>> {
122        let (n_samples, _n_features) = x.dim();
123        let codes = Array2::zeros((n_samples, self.config.n_components));
124        Ok(codes)
125    }
126}
127
128// Algorithm-specific implementations (placeholders)
129pub struct OnlineGradientDescent;
130pub struct OnlineKSvd;
131pub struct AdaptiveDictionaryLearning;
132
133// Type alias for backward compatibility
134pub type TrainedOnlineDictionaryLearning = OnlineDictionaryLearning<Trained>;