use scirs2_core::ndarray::Array2;
use scirs2_core::random::thread_rng;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use sklears_core::{
error::{Result, SklearsError},
traits::{Estimator, Fit, Trained, Transform, Untrained},
types::Float,
};
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum OnlineDictLearningAlgorithm {
SGD,
OnlineKSVD,
Adaptive,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct OnlineDictLearningConfig {
pub n_components: usize,
pub learning_rate: Float,
pub batch_size: usize,
pub algorithm: OnlineDictLearningAlgorithm,
}
impl Default for OnlineDictLearningConfig {
fn default() -> Self {
Self {
n_components: 100,
learning_rate: 0.01,
batch_size: 10,
algorithm: OnlineDictLearningAlgorithm::SGD,
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct OnlineDictionaryLearning<State = Untrained> {
config: OnlineDictLearningConfig,
state: std::marker::PhantomData<State>,
components_: Option<Array2<Float>>,
n_samples_seen_: Option<usize>,
}
impl OnlineDictionaryLearning<Untrained> {
pub fn new(config: OnlineDictLearningConfig) -> Self {
Self {
config,
state: std::marker::PhantomData,
components_: None,
n_samples_seen_: None,
}
}
}
impl OnlineDictionaryLearning<Trained> {
pub fn components(&self) -> &Array2<Float> {
self.components_.as_ref().expect("Model is trained")
}
pub fn n_samples_seen(&self) -> usize {
self.n_samples_seen_.expect("Model is trained")
}
}
impl Estimator for OnlineDictionaryLearning<Untrained> {
type Config = OnlineDictLearningConfig;
type Error = SklearsError;
type Float = Float;
fn config(&self) -> &Self::Config {
&self.config
}
}
impl Fit<Array2<Float>, ()> for OnlineDictionaryLearning<Untrained> {
type Fitted = OnlineDictionaryLearning<Trained>;
fn fit(self, x: &Array2<Float>, _y: &()) -> Result<Self::Fitted> {
let (_n_samples, n_features) = x.dim();
let mut rng = thread_rng();
let mut components = Array2::zeros((self.config.n_components, n_features));
for i in 0..self.config.n_components {
for j in 0..n_features {
components[[i, j]] = rng.random::<Float>() - 0.5;
}
}
Ok(OnlineDictionaryLearning {
config: self.config,
state: std::marker::PhantomData,
components_: Some(components),
n_samples_seen_: Some(x.nrows()),
})
}
}
impl Transform<Array2<Float>, Array2<Float>> for OnlineDictionaryLearning<Trained> {
fn transform(&self, x: &Array2<Float>) -> Result<Array2<Float>> {
let (n_samples, _n_features) = x.dim();
let codes = Array2::zeros((n_samples, self.config.n_components));
Ok(codes)
}
}
pub struct OnlineGradientDescent;
pub struct OnlineKSvd;
pub struct AdaptiveDictionaryLearning;
pub type TrainedOnlineDictionaryLearning = OnlineDictionaryLearning<Trained>;