use scirs2_core::ndarray::{Array1, Array2, ArrayView2, Axis};
use scirs2_core::random::rngs::StdRng;
use scirs2_core::random::thread_rng;
use scirs2_core::random::SeedableRng;
use scirs2_core::RngExt;
use sklears_core::{
error::{Result as SklResult, SklearsError},
traits::{Estimator, Fit, Transform, Untrained},
types::Float,
};
#[allow(non_snake_case)]
#[cfg(test)]
mod tests;
pub mod quality_metrics;
pub use quality_metrics::*;
pub mod stress_testing;
pub use stress_testing::*;
pub mod geodesic_distance;
pub use geodesic_distance::*;
pub mod diffusion_distance;
pub use diffusion_distance::*;
pub mod riemannian;
pub use riemannian::*;
pub mod topological;
pub use topological::*;
#[derive(Debug, Clone)]
pub struct SparseCoding<S = Untrained> {
state: S,
n_components: usize,
alpha: f64,
max_iter: usize,
tol: f64,
random_state: Option<u64>,
}
impl Default for SparseCoding<Untrained> {
fn default() -> Self {
Self::new()
}
}
impl SparseCoding<Untrained> {
pub fn new() -> Self {
Self {
state: Untrained,
n_components: 100,
alpha: 1.0,
max_iter: 1000,
tol: 1e-8,
random_state: None,
}
}
pub fn n_components(mut self, n_components: usize) -> Self {
self.n_components = n_components;
self
}
pub fn alpha(mut self, alpha: f64) -> Self {
self.alpha = alpha;
self
}
pub fn max_iter(mut self, max_iter: usize) -> Self {
self.max_iter = max_iter;
self
}
pub fn tol(mut self, tol: f64) -> Self {
self.tol = tol;
self
}
pub fn random_state(mut self, random_state: u64) -> Self {
self.random_state = Some(random_state);
self
}
fn soft_threshold(x: f64, lambda: f64) -> f64 {
if x > lambda {
x - lambda
} else if x < -lambda {
x + lambda
} else {
0.0
}
}
}
#[derive(Debug, Clone)]
pub struct SCTrained {
dictionary: Array2<f64>,
mean: Array1<f64>,
}
impl Estimator for SparseCoding<Untrained> {
type Config = ();
type Error = SklearsError;
type Float = Float;
fn config(&self) -> &Self::Config {
&()
}
}
impl Fit<ArrayView2<'_, Float>, ()> for SparseCoding<Untrained> {
type Fitted = SparseCoding<SCTrained>;
fn fit(self, x: &ArrayView2<'_, Float>, _y: &()) -> SklResult<Self::Fitted> {
let (n_samples, n_features) = x.dim();
if self.n_components > n_features {
return Err(SklearsError::InvalidInput(
"n_components cannot be larger than n_features".to_string(),
));
}
let x_f64 = x.mapv(|v| v);
let mean = x_f64.mean_axis(Axis(0)).expect("operation should succeed");
let x_centered = &x_f64
- &mean
.view()
.broadcast(x_f64.dim())
.expect("operation should succeed");
let mut rng = if let Some(seed) = self.random_state {
StdRng::seed_from_u64(seed)
} else {
StdRng::seed_from_u64(thread_rng().random::<u64>())
};
let mut dictionary = Array2::<f64>::zeros((n_features, self.n_components));
for mut col in dictionary.columns_mut() {
for elem in col.iter_mut() {
*elem = rng.sample(scirs2_core::StandardNormal);
}
let norm = col.dot(&col).sqrt();
if norm > 0.0 {
col /= norm;
}
}
for _iter in 0..self.max_iter {
let mut max_change = 0.0f64;
for k in 0..self.n_components {
let mut residual = x_centered.clone();
for j in 0..self.n_components {
if j != k {
let atom_j = dictionary.column(j);
let mut codes_j = Array1::zeros(n_samples);
for i in 0..n_samples {
let dot_product = residual.row(i).dot(&atom_j);
codes_j[i] = Self::soft_threshold(dot_product, self.alpha);
}
for i in 0..n_samples {
let mut row = residual.row_mut(i);
row.scaled_add(-codes_j[i], &atom_j);
}
}
}
let mut new_atom = Array1::zeros(n_features);
let mut total_code = 0.0;
for i in 0..n_samples {
let code_k = Self::soft_threshold(
residual.row(i).dot(&dictionary.column(k)),
self.alpha,
);
if code_k.abs() > 1e-12 {
new_atom.scaled_add(code_k, &residual.row(i));
total_code += code_k * code_k;
}
}
if total_code > 1e-12 {
new_atom /= total_code;
let norm = new_atom.dot(&new_atom).sqrt();
if norm > 1e-12 {
new_atom /= norm;
}
let change = (&new_atom - &dictionary.column(k)).mapv(|x| x.abs()).sum();
max_change = max_change.max(change);
dictionary.column_mut(k).assign(&new_atom);
}
}
if max_change < self.tol {
break;
}
}
Ok(SparseCoding {
state: SCTrained { dictionary, mean },
n_components: self.n_components,
alpha: self.alpha,
max_iter: self.max_iter,
tol: self.tol,
random_state: self.random_state,
})
}
}
impl Transform<ArrayView2<'_, Float>, Array2<f64>> for SparseCoding<SCTrained> {
fn transform(&self, x: &ArrayView2<'_, Float>) -> SklResult<Array2<f64>> {
let (n_samples, _) = x.dim();
let x_f64 = x.mapv(|v| v);
let x_centered = &x_f64
- &self
.state
.mean
.view()
.broadcast(x_f64.dim())
.expect("operation should succeed");
let mut codes = Array2::zeros((n_samples, self.n_components));
for i in 0..n_samples {
let sample = x_centered.row(i);
let mut code = Array1::<f64>::zeros(self.n_components);
for _ in 0..100 {
let mut max_change = 0.0f64;
for k in 0..self.n_components {
let mut residual = sample.to_owned();
for j in 0..self.n_components {
if j != k {
let atom_j = self.state.dictionary.column(j);
residual.scaled_add(-code[j], &atom_j);
}
}
let atom_k = self.state.dictionary.column(k);
let new_code_k =
SparseCoding::soft_threshold(residual.dot(&atom_k), self.alpha);
let change = (new_code_k - code[k]).abs();
max_change = max_change.max(change);
code[k] = new_code_k;
}
if max_change < 1e-6 {
break;
}
}
codes.row_mut(i).assign(&code);
}
Ok(codes)
}
}
pub mod tsne;
pub mod isomap;
pub mod lle;
pub mod mds;
pub mod laplacian_eigenmaps;
pub mod umap;
pub mod diffusion_maps;
pub mod hessian_lle;
pub mod ltsa;
pub mod mvu;
pub mod sne;
pub mod symmetric_sne;
pub mod parametric_tsne;
pub mod heavy_tailed_symmetric_sne;
pub mod spectral_embedding;
pub mod random_walk_embedding;
pub mod node2vec;
pub mod deepwalk;
pub mod dictionary_learning;
pub mod minibatch_tsne;
pub mod minibatch_umap;
pub mod distance_kernels;
pub mod graph_neural_networks;
pub mod random_projections;
pub mod similarity;
pub mod hierarchical;
pub mod temporal;
pub mod robust;
pub use tsne::{TsneTrained, TSNE};
pub use isomap::{Isomap, IsomapTrained};
pub use lle::{LleTrained, LocallyLinearEmbedding};
pub use mds::{MdsTrained, MDS};
pub use laplacian_eigenmaps::{LaplacianEigenmaps, LaplacianTrained};
pub use umap::{UmapTrained, UMAP};
pub use diffusion_maps::{DiffusionMaps, DiffusionMapsTrained};
pub use deepwalk::{DeepWalk, DeepWalkTrained};
pub use dictionary_learning::{DLTrained, DictionaryLearning};
pub use heavy_tailed_symmetric_sne::{HeavyTailedSymmetricSNE, HeavyTailedSymmetricSneTrained};
pub use hessian_lle::{HessianLLE, HessianLleTrained};
pub use ltsa::{LtsaTrained, LTSA};
pub use minibatch_tsne::{MBTSNETrained, MiniBatchTSNE};
pub use minibatch_umap::{MBUMAPTrained, MiniBatchUMAP};
pub use mvu::{MvuTrained, MVU};
pub use node2vec::{Node2Vec, Node2VecTrained};
pub use parametric_tsne::{ParametricTSNE, ParametricTsneTrained};
pub use random_walk_embedding::{RandomWalkEmbedding, RandomWalkEmbeddingTrained};
pub use sne::{SneTrained, SNE};
pub use spectral_embedding::{SpectralEmbedding, SpectralEmbeddingTrained};
pub use symmetric_sne::{SymmetricSNE, SymmetricSneTrained};
pub use distance_kernels::*;
pub use graph_neural_networks::*;
pub use random_projections::*;
pub use similarity::*;
pub use hierarchical::EmbeddingQuality as HierarchicalEmbeddingQuality;
pub use hierarchical::{
AdaptationStep, AdaptiveResolutionManifold, HierarchicalManifold, MultiScaleEmbedding,
TrainedAdaptiveResolutionManifold, TrainedHierarchicalManifold, TrainedMultiScaleEmbedding,
};
pub use temporal::*;
pub use robust::*;
pub mod multi_view;
pub mod nystrom;
pub mod compressed_sensing;
pub mod parallel_knn;
pub mod stochastic;
pub use multi_view::*;
pub use nystrom::*;
pub use compressed_sensing::*;
pub use parallel_knn::*;
pub use stochastic::*;
pub mod benchmark_datasets;
pub mod timing_utilities;
pub mod memory_profiler;
pub mod simd_distance;
pub mod validation;
pub mod visualization;
#[cfg(feature = "gpu")]
pub mod gpu_acceleration;
pub mod type_safe_manifolds;
pub mod zero_cost_abstractions;
pub mod reference_tests;
pub mod stable_eigenvalue;
pub mod robust_optimization;
pub mod condition_monitoring;
pub mod manifold_traits;
pub mod fluent_api;
pub mod extensible_metrics;
pub mod type_safe_geometry;
pub use manifold_traits::DistanceMetric as BasicDistanceMetric;
pub use manifold_traits::EmbeddingQuality as EmbeddingQualityTrait;
pub use manifold_traits::ManifoldPipeline as BasicManifoldPipeline;
pub use manifold_traits::SpectralEmbedding as SpectralEmbeddingTrait;
pub use manifold_traits::{
IterativeOptimization, KernelBased, ManifoldComplexity, ManifoldConfig, ManifoldFactory,
ManifoldLearning, ManifoldPresets, NeighborhoodBased, ProbabilisticEmbedding,
RandomizedAlgorithm,
};
pub use fluent_api::*;
pub use extensible_metrics::*;
pub use type_safe_geometry::*;
pub use visualization::*;
#[cfg(feature = "serialization")]
pub mod serialization;
#[cfg(feature = "serialization")]
pub mod serialization_impl;
#[cfg(feature = "serialization")]
pub use serialization::*;
pub mod plugin_architecture;
pub use plugin_architecture::utils as plugin_utils;
pub use plugin_architecture::ParameterValue as PluginParameterValue;
pub use plugin_architecture::{
CustomManifoldLearner, CustomManifoldWrapper, CustomModelMetadata, ManifoldPlugin,
ParameterConstraints, ParameterDefinition, ParameterType, PluginFeature, PluginMetadata,
PluginParameters, PluginRegistry,
};
pub mod information_theory;
pub use information_theory::*;
pub mod optimal_transport;
pub use optimal_transport::*;
pub mod iterative_refinement;
pub use iterative_refinement::*;
pub mod pipeline_middleware;
pub use pipeline_middleware::*;
pub mod embedding_callbacks;
pub use embedding_callbacks::*;
pub mod category_theory;
pub use category_theory::*;
pub mod performance_optimization;
pub use performance_optimization::*;
pub mod deep_learning;
pub use deep_learning::{
AutoencoderManifold, NeuralODE, ODESolverType, PriorType, TrainedAAE, TrainedAutoencoder,
TrainedCNF, TrainedNODE, TrainedVAE, VariationalAutoencoder,
};
pub mod computer_vision;
pub use computer_vision::*;
pub mod adversarial;
pub use adversarial::*;
pub mod continuous_normalizing_flows;
pub use continuous_normalizing_flows::*;
pub mod nlp;
pub use nlp::*;
pub mod quantum;
pub use quantum::*;
pub mod causal;
pub use causal::*;
pub mod bioinformatics;
pub use bioinformatics::*;