quantrs2_ml/dimensionality_reduction/
core.rs1use crate::error::{MLError, Result};
4use scirs2_core::ndarray::{Array1, Array2};
5
6use super::config::*;
7use super::metrics::*;
8
9#[derive(Debug)]
11pub struct QuantumDimensionalityReducer {
12 pub algorithm: DimensionalityReductionAlgorithm,
14 pub qpca_config: Option<QPCAConfig>,
16 pub qica_config: Option<QICAConfig>,
18 pub qtsne_config: Option<QtSNEConfig>,
20 pub qumap_config: Option<QUMAPConfig>,
22 pub qlda_config: Option<QLDAConfig>,
24 pub qfa_config: Option<QFactorAnalysisConfig>,
26 pub qcca_config: Option<QCCAConfig>,
28 pub qnmf_config: Option<QNMFConfig>,
30 pub autoencoder_config: Option<QAutoencoderConfig>,
32 pub manifold_config: Option<QManifoldConfig>,
34 pub kernel_pca_config: Option<QKernelPCAConfig>,
36 pub feature_selection_config: Option<QFeatureSelectionConfig>,
38 pub specialized_config: Option<QSpecializedConfig>,
40 pub trained_state: Option<DRTrainedState>,
42}
43
44impl QuantumDimensionalityReducer {
45 pub fn new(algorithm: DimensionalityReductionAlgorithm) -> Self {
47 Self {
48 algorithm,
49 qpca_config: None,
50 qica_config: None,
51 qtsne_config: None,
52 qumap_config: None,
53 qlda_config: None,
54 qfa_config: None,
55 qcca_config: None,
56 qnmf_config: None,
57 autoencoder_config: None,
58 manifold_config: None,
59 kernel_pca_config: None,
60 feature_selection_config: None,
61 specialized_config: None,
62 trained_state: None,
63 }
64 }
65
66 pub fn with_qpca_config(mut self, config: QPCAConfig) -> Self {
68 self.qpca_config = Some(config);
69 self
70 }
71
72 pub fn with_qica_config(mut self, config: QICAConfig) -> Self {
74 self.qica_config = Some(config);
75 self
76 }
77
78 pub fn with_qtsne_config(mut self, config: QtSNEConfig) -> Self {
80 self.qtsne_config = Some(config);
81 self
82 }
83
84 pub fn with_qumap_config(mut self, config: QUMAPConfig) -> Self {
86 self.qumap_config = Some(config);
87 self
88 }
89
90 pub fn with_qlda_config(mut self, config: QLDAConfig) -> Self {
92 self.qlda_config = Some(config);
93 self
94 }
95
96 pub fn with_autoencoder_config(mut self, config: QAutoencoderConfig) -> Self {
98 self.autoencoder_config = Some(config);
99 self
100 }
101
102 pub fn fit(&mut self, data: &Array2<f64>) -> Result<()> {
104 match self.algorithm {
105 DimensionalityReductionAlgorithm::QPCA => self.fit_qpca(data),
106 DimensionalityReductionAlgorithm::QICA => self.fit_qica(data),
107 DimensionalityReductionAlgorithm::QtSNE => self.fit_qtsne(data),
108 DimensionalityReductionAlgorithm::QUMAP => self.fit_qumap(data),
109 DimensionalityReductionAlgorithm::QLDA => self.fit_qlda(data),
110 DimensionalityReductionAlgorithm::QVAE => self.fit_qvae(data),
111 DimensionalityReductionAlgorithm::QDenoisingAE => self.fit_qdenoising_ae(data),
112 DimensionalityReductionAlgorithm::QSparseAE => self.fit_qsparse_ae(data),
113 DimensionalityReductionAlgorithm::QManifoldLearning => self.fit_qmanifold(data),
114 DimensionalityReductionAlgorithm::QKernelPCA => self.fit_qkernel_pca(data),
115 _ => {
116 self.fit_placeholder(data)
118 }
119 }
120 }
121
122 pub fn transform(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
124 if self.trained_state.is_none() {
125 return Err(MLError::ModelNotTrained(
126 "Model must be fitted before transform".to_string(),
127 ));
128 }
129
130 match self.algorithm {
131 DimensionalityReductionAlgorithm::QPCA => self.transform_qpca(data),
132 DimensionalityReductionAlgorithm::QICA => self.transform_qica(data),
133 DimensionalityReductionAlgorithm::QtSNE => self.transform_qtsne(data),
134 DimensionalityReductionAlgorithm::QUMAP => self.transform_qumap(data),
135 DimensionalityReductionAlgorithm::QLDA => self.transform_qlda(data),
136 DimensionalityReductionAlgorithm::QVAE => self.transform_qvae(data),
137 DimensionalityReductionAlgorithm::QDenoisingAE => self.transform_qdenoising_ae(data),
138 DimensionalityReductionAlgorithm::QSparseAE => self.transform_qsparse_ae(data),
139 DimensionalityReductionAlgorithm::QManifoldLearning => self.transform_qmanifold(data),
140 DimensionalityReductionAlgorithm::QKernelPCA => self.transform_qkernel_pca(data),
141 _ => {
142 self.transform_placeholder(data)
144 }
145 }
146 }
147
148 pub fn fit_transform(&mut self, data: &Array2<f64>) -> Result<Array2<f64>> {
150 self.fit(data)?;
151 self.transform(data)
152 }
153
154 pub fn get_trained_state(&self) -> Option<&DRTrainedState> {
156 self.trained_state.as_ref()
157 }
158
159 pub fn explained_variance_ratio(&self) -> Option<&Array1<f64>> {
161 self.trained_state
162 .as_ref()
163 .map(|state| &state.explained_variance_ratio)
164 }
165
166 pub fn components(&self) -> Option<&Array2<f64>> {
168 self.trained_state.as_ref().map(|state| &state.components)
169 }
170
171 pub fn inverse_transform(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
173 if let Some(state) = &self.trained_state {
174 let centered = data.dot(&state.components);
176 let reconstructed = ¢ered + &state.mean;
177 Ok(reconstructed)
178 } else {
179 Err(MLError::ModelNotTrained(
180 "Model must be fitted before inverse transform".to_string(),
181 ))
182 }
183 }
184
185 fn fit_qpca(&mut self, data: &Array2<f64>) -> Result<()> {
188 use super::linear::QPCA;
189 let binding = QPCAConfig::default();
190 let config = self.qpca_config.as_ref().unwrap_or(&binding);
191 let mut qpca = QPCA::new(config.clone());
192 qpca.fit(data)?;
193 self.trained_state = qpca.get_trained_state();
194 Ok(())
195 }
196
197 fn fit_qica(&mut self, data: &Array2<f64>) -> Result<()> {
198 use super::linear::QICA;
199 let binding = QICAConfig::default();
200 let config = self.qica_config.as_ref().unwrap_or(&binding);
201 let mut qica = QICA::new(config.clone());
202 qica.fit(data)?;
203 self.trained_state = qica.get_trained_state();
204 Ok(())
205 }
206
207 fn fit_qtsne(&mut self, data: &Array2<f64>) -> Result<()> {
208 use super::manifold::QtSNE;
209 let binding = QtSNEConfig::default();
210 let config = self.qtsne_config.as_ref().unwrap_or(&binding);
211 let mut qtsne = QtSNE::new(config.clone());
212 qtsne.fit(data)?;
213 self.trained_state = qtsne.get_trained_state();
214 Ok(())
215 }
216
217 fn fit_qumap(&mut self, data: &Array2<f64>) -> Result<()> {
218 use super::manifold::QUMAP;
219 let binding = QUMAPConfig::default();
220 let config = self.qumap_config.as_ref().unwrap_or(&binding);
221 let mut qumap = QUMAP::new(config.clone());
222 qumap.fit(data)?;
223 self.trained_state = qumap.get_trained_state();
224 Ok(())
225 }
226
227 fn fit_qlda(&mut self, data: &Array2<f64>) -> Result<()> {
228 use super::linear::QLDA;
229 let default_config = QLDAConfig::default();
230 let config = self.qlda_config.as_ref().unwrap_or(&default_config);
231 let mut qlda = QLDA::new(config.clone());
232 qlda.fit(data)?;
233 self.trained_state = qlda.get_trained_state();
234 Ok(())
235 }
236
237 fn fit_qvae(&mut self, data: &Array2<f64>) -> Result<()> {
238 use super::autoencoders::QVAE;
239 let default_config = QAutoencoderConfig::default();
240 let config = self.autoencoder_config.as_ref().unwrap_or(&default_config);
241 let mut qvae = QVAE::new(config.clone());
242 qvae.fit(data)?;
243 self.trained_state = qvae.get_trained_state();
244 Ok(())
245 }
246
247 fn fit_qdenoising_ae(&mut self, data: &Array2<f64>) -> Result<()> {
248 use super::autoencoders::QDenoisingAE;
249 let default_config = QAutoencoderConfig::default();
250 let config = self.autoencoder_config.as_ref().unwrap_or(&default_config);
251 let mut qdenoising = QDenoisingAE::new(config.clone());
252 qdenoising.fit(data)?;
253 self.trained_state = qdenoising.get_trained_state();
254 Ok(())
255 }
256
257 fn fit_qsparse_ae(&mut self, data: &Array2<f64>) -> Result<()> {
258 use super::autoencoders::QSparseAE;
259 let default_config = QAutoencoderConfig::default();
260 let config = self.autoencoder_config.as_ref().unwrap_or(&default_config);
261 let mut qsparse = QSparseAE::new(config.clone());
262 qsparse.fit(data)?;
263 self.trained_state = qsparse.get_trained_state();
264 Ok(())
265 }
266
267 fn fit_qmanifold(&mut self, data: &Array2<f64>) -> Result<()> {
268 use super::manifold::QManifoldLearning;
269 let default_config = QManifoldConfig::default();
270 let config = self.manifold_config.as_ref().unwrap_or(&default_config);
271 let mut qmanifold = QManifoldLearning::new(config.clone());
272 qmanifold.fit(data)?;
273 self.trained_state = qmanifold.get_trained_state();
274 Ok(())
275 }
276
277 fn fit_qkernel_pca(&mut self, data: &Array2<f64>) -> Result<()> {
278 use super::linear::QKernelPCA;
279 let default_config = QKernelPCAConfig::default();
280 let config = self.kernel_pca_config.as_ref().unwrap_or(&default_config);
281 let mut qkernel_pca = QKernelPCA::new(config.clone());
282 qkernel_pca.fit(data)?;
283 self.trained_state = qkernel_pca.get_trained_state();
284 Ok(())
285 }
286
287 fn fit_placeholder(&mut self, data: &Array2<f64>) -> Result<()> {
288 let n_samples = data.nrows();
290 let n_features = data.ncols();
291 let n_components = (n_features / 2).max(1);
292
293 let components = Array2::eye(n_components);
294 let explained_variance_ratio =
295 Array1::from_vec((0..n_components).map(|i| 1.0 / (i + 1) as f64).collect());
296 let mean = data.mean_axis(scirs2_core::ndarray::Axis(0)).unwrap();
297
298 self.trained_state = Some(DRTrainedState {
299 components,
300 explained_variance_ratio,
301 mean,
302 scale: None,
303 quantum_parameters: std::collections::HashMap::new(),
304 model_parameters: std::collections::HashMap::new(),
305 training_statistics: std::collections::HashMap::new(),
306 });
307
308 Ok(())
309 }
310
311 fn transform_qpca(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
314 let state = self.trained_state.as_ref().unwrap();
315 let centered = data - &state.mean;
316 Ok(centered.dot(&state.components.t()))
317 }
318
319 fn transform_qica(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
320 let state = self.trained_state.as_ref().unwrap();
321 let centered = data - &state.mean;
322 Ok(centered.dot(&state.components.t()))
323 }
324
325 fn transform_qtsne(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
326 let state = self.trained_state.as_ref().unwrap();
327 Ok(Array2::zeros((data.nrows(), state.components.ncols())))
329 }
330
331 fn transform_qumap(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
332 let state = self.trained_state.as_ref().unwrap();
333 Ok(Array2::zeros((data.nrows(), state.components.ncols())))
335 }
336
337 fn transform_qlda(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
338 let state = self.trained_state.as_ref().unwrap();
339 let centered = data - &state.mean;
340 Ok(centered.dot(&state.components.t()))
341 }
342
343 fn transform_qvae(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
344 let state = self.trained_state.as_ref().unwrap();
345 Ok(Array2::zeros((data.nrows(), state.components.ncols())))
347 }
348
349 fn transform_qdenoising_ae(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
350 let state = self.trained_state.as_ref().unwrap();
351 Ok(Array2::zeros((data.nrows(), state.components.ncols())))
353 }
354
355 fn transform_qsparse_ae(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
356 let state = self.trained_state.as_ref().unwrap();
357 Ok(Array2::zeros((data.nrows(), state.components.ncols())))
359 }
360
361 fn transform_qmanifold(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
362 let state = self.trained_state.as_ref().unwrap();
363 Ok(Array2::zeros((data.nrows(), state.components.ncols())))
365 }
366
367 fn transform_qkernel_pca(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
368 let state = self.trained_state.as_ref().unwrap();
369 Ok(Array2::zeros((data.nrows(), state.components.ncols())))
371 }
372
373 fn transform_placeholder(&self, data: &Array2<f64>) -> Result<Array2<f64>> {
374 let state = self.trained_state.as_ref().unwrap();
375 let centered = data - &state.mean;
376 Ok(centered.dot(&state.components.t()))
377 }
378}