1use scirs2_core::ndarray::{Array1, Array2, Axis};
3use scirs2_core::random::essentials::{Normal as RandNormal, Uniform as RandUniform};
4use scirs2_core::random::rngs::StdRng as RealStdRng;
5use scirs2_core::random::Rng;
6use scirs2_core::random::{thread_rng, SeedableRng};
7use scirs2_core::Cauchy;
8use sklears_core::{
9 error::{Result, SklearsError},
10 prelude::{Fit, Transform},
11 traits::{Estimator, Trained, Untrained},
12 types::Float,
13};
14use std::marker::PhantomData;
15
16#[derive(Debug, Clone)]
42pub struct RBFSampler<State = Untrained> {
44 pub gamma: Float,
46 pub n_components: usize,
48 pub random_state: Option<u64>,
50
51 random_weights_: Option<Array2<Float>>,
53 random_offset_: Option<Array1<Float>>,
54
55 _state: PhantomData<State>,
56}
57
58impl RBFSampler<Untrained> {
59 pub fn new(n_components: usize) -> Self {
61 Self {
62 gamma: 1.0,
63 n_components,
64 random_state: None,
65 random_weights_: None,
66 random_offset_: None,
67 _state: PhantomData,
68 }
69 }
70
71 pub fn gamma(mut self, gamma: Float) -> Self {
73 self.gamma = gamma;
74 self
75 }
76
77 pub fn random_state(mut self, seed: u64) -> Self {
79 self.random_state = Some(seed);
80 self
81 }
82}
83
84impl Estimator for RBFSampler<Untrained> {
85 type Config = ();
86 type Error = SklearsError;
87 type Float = Float;
88
89 fn config(&self) -> &Self::Config {
90 &()
91 }
92}
93
94impl Fit<Array2<Float>, ()> for RBFSampler<Untrained> {
95 type Fitted = RBFSampler<Trained>;
96
97 fn fit(self, x: &Array2<Float>, _y: &()) -> Result<Self::Fitted> {
98 let (_, n_features) = x.dim();
99
100 if self.gamma <= 0.0 {
101 return Err(SklearsError::InvalidInput(
102 "gamma must be positive".to_string(),
103 ));
104 }
105
106 if self.n_components == 0 {
107 return Err(SklearsError::InvalidInput(
108 "n_components must be positive".to_string(),
109 ));
110 }
111
112 let mut rng = if let Some(seed) = self.random_state {
113 RealStdRng::seed_from_u64(seed)
114 } else {
115 RealStdRng::from_seed(thread_rng().gen())
116 };
117
118 let normal = RandNormal::new(0.0, (2.0 * self.gamma).sqrt()).map_err(|_| {
120 SklearsError::InvalidInput("Failed to create normal distribution".to_string())
121 })?;
122 let mut random_weights = Array2::zeros((n_features, self.n_components));
123 for mut col in random_weights.columns_mut() {
124 for val in col.iter_mut() {
125 *val = rng.sample(normal);
126 }
127 }
128
129 let uniform = RandUniform::new(0.0, 2.0 * std::f64::consts::PI).map_err(|_| {
131 SklearsError::InvalidInput("Failed to create uniform distribution".to_string())
132 })?;
133 let mut random_offset = Array1::zeros(self.n_components);
134 for val in random_offset.iter_mut() {
135 *val = rng.sample(uniform);
136 }
137
138 Ok(RBFSampler {
139 gamma: self.gamma,
140 n_components: self.n_components,
141 random_state: self.random_state,
142 random_weights_: Some(random_weights),
143 random_offset_: Some(random_offset),
144 _state: PhantomData,
145 })
146 }
147}
148
149impl Transform<Array2<Float>, Array2<Float>> for RBFSampler<Trained> {
150 fn transform(&self, x: &Array2<Float>) -> Result<Array2<Float>> {
151 let (_n_samples, n_features) = x.dim();
152 let weights = self
153 .random_weights_
154 .as_ref()
155 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))?;
156 let offset = self
157 .random_offset_
158 .as_ref()
159 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))?;
160
161 if n_features != weights.nrows() {
162 return Err(SklearsError::InvalidInput(format!(
163 "X has {} features, but RBFSampler was fitted with {} features",
164 n_features,
165 weights.nrows()
166 )));
167 }
168
169 let projection = x.dot(weights) + offset.view().insert_axis(Axis(0));
171
172 let normalization = (2.0 / self.n_components as Float).sqrt();
174 let result = projection.mapv(|v| normalization * v.cos());
175
176 Ok(result)
177 }
178}
179
180impl RBFSampler<Trained> {
181 pub fn random_weights(&self) -> Result<&Array2<Float>> {
183 self.random_weights_
184 .as_ref()
185 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))
186 }
187
188 pub fn random_offset(&self) -> Result<&Array1<Float>> {
190 self.random_offset_
191 .as_ref()
192 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))
193 }
194}
195
196#[derive(Debug, Clone)]
222pub struct LaplacianSampler<State = Untrained> {
224 pub gamma: Float,
226 pub n_components: usize,
228 pub random_state: Option<u64>,
230
231 random_weights_: Option<Array2<Float>>,
233 random_offset_: Option<Array1<Float>>,
234
235 _state: PhantomData<State>,
236}
237
238impl LaplacianSampler<Untrained> {
239 pub fn new(n_components: usize) -> Self {
241 Self {
242 gamma: 1.0,
243 n_components,
244 random_state: None,
245 random_weights_: None,
246 random_offset_: None,
247 _state: PhantomData,
248 }
249 }
250
251 pub fn gamma(mut self, gamma: Float) -> Self {
253 self.gamma = gamma;
254 self
255 }
256
257 pub fn random_state(mut self, seed: u64) -> Self {
259 self.random_state = Some(seed);
260 self
261 }
262}
263
264impl Estimator for LaplacianSampler<Untrained> {
265 type Config = ();
266 type Error = SklearsError;
267 type Float = Float;
268
269 fn config(&self) -> &Self::Config {
270 &()
271 }
272}
273
274impl Fit<Array2<Float>, ()> for LaplacianSampler<Untrained> {
275 type Fitted = LaplacianSampler<Trained>;
276
277 fn fit(self, x: &Array2<Float>, _y: &()) -> Result<Self::Fitted> {
278 let (_, n_features) = x.dim();
279
280 if self.gamma <= 0.0 {
281 return Err(SklearsError::InvalidInput(
282 "gamma must be positive".to_string(),
283 ));
284 }
285
286 if self.n_components == 0 {
287 return Err(SklearsError::InvalidInput(
288 "n_components must be positive".to_string(),
289 ));
290 }
291
292 let mut rng = if let Some(seed) = self.random_state {
293 RealStdRng::seed_from_u64(seed)
294 } else {
295 RealStdRng::from_seed(thread_rng().gen())
296 };
297
298 let cauchy = Cauchy::new(0.0, self.gamma).map_err(|_| {
300 SklearsError::InvalidInput("Failed to create Cauchy distribution".to_string())
301 })?;
302 let mut random_weights = Array2::zeros((n_features, self.n_components));
303 for mut col in random_weights.columns_mut() {
304 for val in col.iter_mut() {
305 *val = rng.sample(cauchy);
306 }
307 }
308
309 let uniform = RandUniform::new(0.0, 2.0 * std::f64::consts::PI).map_err(|_| {
311 SklearsError::InvalidInput("Failed to create uniform distribution".to_string())
312 })?;
313 let mut random_offset = Array1::zeros(self.n_components);
314 for val in random_offset.iter_mut() {
315 *val = rng.sample(uniform);
316 }
317
318 Ok(LaplacianSampler {
319 gamma: self.gamma,
320 n_components: self.n_components,
321 random_state: self.random_state,
322 random_weights_: Some(random_weights),
323 random_offset_: Some(random_offset),
324 _state: PhantomData,
325 })
326 }
327}
328
329impl Transform<Array2<Float>, Array2<Float>> for LaplacianSampler<Trained> {
330 fn transform(&self, x: &Array2<Float>) -> Result<Array2<Float>> {
331 let (_n_samples, n_features) = x.dim();
332 let weights = self
333 .random_weights_
334 .as_ref()
335 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))?;
336 let offset = self
337 .random_offset_
338 .as_ref()
339 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))?;
340
341 if n_features != weights.nrows() {
342 return Err(SklearsError::InvalidInput(format!(
343 "X has {} features, but LaplacianSampler was fitted with {} features",
344 n_features,
345 weights.nrows()
346 )));
347 }
348
349 let projection = x.dot(weights) + offset.view().insert_axis(Axis(0));
351
352 let normalization = (2.0 / self.n_components as Float).sqrt();
354 let result = projection.mapv(|v| normalization * v.cos());
355
356 Ok(result)
357 }
358}
359
360impl LaplacianSampler<Trained> {
361 pub fn random_weights(&self) -> Result<&Array2<Float>> {
363 self.random_weights_
364 .as_ref()
365 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))
366 }
367
368 pub fn random_offset(&self) -> Result<&Array1<Float>> {
370 self.random_offset_
371 .as_ref()
372 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))
373 }
374}
375
376#[derive(Debug, Clone)]
404pub struct PolynomialSampler<State = Untrained> {
406 pub gamma: Float,
408 pub coef0: Float,
410 pub degree: u32,
412 pub n_components: usize,
414 pub random_state: Option<u64>,
416
417 random_weights_: Option<Array2<Float>>,
419 random_offset_: Option<Array1<Float>>,
420
421 _state: PhantomData<State>,
422}
423
424impl PolynomialSampler<Untrained> {
425 pub fn new(n_components: usize) -> Self {
427 Self {
428 gamma: 1.0,
429 coef0: 1.0,
430 degree: 3,
431 n_components,
432 random_state: None,
433 random_weights_: None,
434 random_offset_: None,
435 _state: PhantomData,
436 }
437 }
438
439 pub fn gamma(mut self, gamma: Float) -> Self {
441 self.gamma = gamma;
442 self
443 }
444
445 pub fn coef0(mut self, coef0: Float) -> Self {
447 self.coef0 = coef0;
448 self
449 }
450
451 pub fn degree(mut self, degree: u32) -> Self {
453 self.degree = degree;
454 self
455 }
456
457 pub fn random_state(mut self, seed: u64) -> Self {
459 self.random_state = Some(seed);
460 self
461 }
462}
463
464impl Estimator for PolynomialSampler<Untrained> {
465 type Config = ();
466 type Error = SklearsError;
467 type Float = Float;
468
469 fn config(&self) -> &Self::Config {
470 &()
471 }
472}
473
474impl Fit<Array2<Float>, ()> for PolynomialSampler<Untrained> {
475 type Fitted = PolynomialSampler<Trained>;
476
477 fn fit(self, x: &Array2<Float>, _y: &()) -> Result<Self::Fitted> {
478 let (_, n_features) = x.dim();
479
480 if self.gamma <= 0.0 {
481 return Err(SklearsError::InvalidInput(
482 "gamma must be positive".to_string(),
483 ));
484 }
485
486 if self.degree == 0 {
487 return Err(SklearsError::InvalidInput(
488 "degree must be positive".to_string(),
489 ));
490 }
491
492 if self.n_components == 0 {
493 return Err(SklearsError::InvalidInput(
494 "n_components must be positive".to_string(),
495 ));
496 }
497
498 let mut rng = if let Some(seed) = self.random_state {
499 RealStdRng::seed_from_u64(seed)
500 } else {
501 RealStdRng::from_seed(thread_rng().gen())
502 };
503
504 let normal = RandNormal::new(0.0, 1.0).map_err(|_| {
507 SklearsError::InvalidInput("Failed to create normal distribution".to_string())
508 })?;
509 let mut random_weights = Array2::zeros((n_features, self.n_components));
510
511 for mut col in random_weights.columns_mut() {
512 for val in col.iter_mut() {
514 *val = rng.sample(normal);
515 }
516 let norm = (col.dot(&col) as Float).sqrt();
517 if norm > 1e-12 {
518 col /= norm;
519 }
520
521 col *= self.gamma.sqrt();
523 }
524
525 let uniform = RandUniform::new(0.0, 2.0 * std::f64::consts::PI).map_err(|_| {
527 SklearsError::InvalidInput("Failed to create uniform distribution".to_string())
528 })?;
529 let mut random_offset = Array1::zeros(self.n_components);
530 for val in random_offset.iter_mut() {
531 *val = rng.sample(uniform);
532 }
533
534 Ok(PolynomialSampler {
535 gamma: self.gamma,
536 coef0: self.coef0,
537 degree: self.degree,
538 n_components: self.n_components,
539 random_state: self.random_state,
540 random_weights_: Some(random_weights),
541 random_offset_: Some(random_offset),
542 _state: PhantomData,
543 })
544 }
545}
546
547impl Transform<Array2<Float>, Array2<Float>> for PolynomialSampler<Trained> {
548 fn transform(&self, x: &Array2<Float>) -> Result<Array2<Float>> {
549 let (_n_samples, n_features) = x.dim();
550 let weights = self
551 .random_weights_
552 .as_ref()
553 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))?;
554 let offset = self
555 .random_offset_
556 .as_ref()
557 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))?;
558
559 if n_features != weights.nrows() {
560 return Err(SklearsError::InvalidInput(format!(
561 "X has {} features, but PolynomialSampler was fitted with {} features",
562 n_features,
563 weights.nrows()
564 )));
565 }
566
567 let projection = x.dot(weights) + offset.view().insert_axis(Axis(0));
569
570 let normalization = (2.0 / self.n_components as Float).sqrt();
573 let result = projection.mapv(|v| {
574 let cos_val = v.cos() + self.coef0;
575 normalization * cos_val.powf(self.degree as Float)
576 });
577
578 Ok(result)
579 }
580}
581
582impl PolynomialSampler<Trained> {
583 pub fn random_weights(&self) -> Result<&Array2<Float>> {
585 self.random_weights_
586 .as_ref()
587 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))
588 }
589
590 pub fn random_offset(&self) -> Result<&Array1<Float>> {
592 self.random_offset_
593 .as_ref()
594 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))
595 }
596
597 pub fn gamma(&self) -> Float {
599 self.gamma
600 }
601
602 pub fn coef0(&self) -> Float {
604 self.coef0
605 }
606
607 pub fn degree(&self) -> u32 {
609 self.degree
610 }
611}
612
613#[derive(Debug, Clone)]
641pub struct ArcCosineSampler<State = Untrained> {
643 pub degree: u32,
645 pub n_components: usize,
647 pub random_state: Option<u64>,
649
650 random_weights_: Option<Array2<Float>>,
652
653 _state: PhantomData<State>,
654}
655
656impl ArcCosineSampler<Untrained> {
657 pub fn new(n_components: usize) -> Self {
659 Self {
660 degree: 1,
661 n_components,
662 random_state: None,
663 random_weights_: None,
664 _state: PhantomData,
665 }
666 }
667
668 pub fn degree(mut self, degree: u32) -> Self {
670 self.degree = degree;
671 self
672 }
673
674 pub fn random_state(mut self, seed: u64) -> Self {
676 self.random_state = Some(seed);
677 self
678 }
679}
680
681impl Estimator for ArcCosineSampler<Untrained> {
682 type Config = ();
683 type Error = SklearsError;
684 type Float = Float;
685
686 fn config(&self) -> &Self::Config {
687 &()
688 }
689}
690
691impl Fit<Array2<Float>, ()> for ArcCosineSampler<Untrained> {
692 type Fitted = ArcCosineSampler<Trained>;
693
694 fn fit(self, x: &Array2<Float>, _y: &()) -> Result<Self::Fitted> {
695 let (_, n_features) = x.dim();
696
697 if self.degree > 2 {
698 return Err(SklearsError::InvalidInput(
699 "degree must be 0, 1, or 2".to_string(),
700 ));
701 }
702
703 if self.n_components == 0 {
704 return Err(SklearsError::InvalidInput(
705 "n_components must be positive".to_string(),
706 ));
707 }
708
709 let mut rng = if let Some(seed) = self.random_state {
710 RealStdRng::seed_from_u64(seed)
711 } else {
712 RealStdRng::from_seed(thread_rng().gen())
713 };
714
715 let normal = RandNormal::new(0.0, 1.0).map_err(|_| {
717 SklearsError::InvalidInput("Failed to create normal distribution".to_string())
718 })?;
719 let mut random_weights = Array2::zeros((n_features, self.n_components));
720
721 for mut col in random_weights.columns_mut() {
722 for val in col.iter_mut() {
723 *val = rng.sample(normal);
724 }
725 }
726
727 Ok(ArcCosineSampler {
728 degree: self.degree,
729 n_components: self.n_components,
730 random_state: self.random_state,
731 random_weights_: Some(random_weights),
732 _state: PhantomData,
733 })
734 }
735}
736
737impl Transform<Array2<Float>, Array2<Float>> for ArcCosineSampler<Trained> {
738 fn transform(&self, x: &Array2<Float>) -> Result<Array2<Float>> {
739 let (_n_samples, n_features) = x.dim();
740 let weights = self
741 .random_weights_
742 .as_ref()
743 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))?;
744
745 if n_features != weights.nrows() {
746 return Err(SklearsError::InvalidInput(format!(
747 "X has {} features, but ArcCosineSampler was fitted with {} features",
748 n_features,
749 weights.nrows()
750 )));
751 }
752
753 let projection = x.dot(weights);
755
756 let normalization = (2.0 / self.n_components as Float).sqrt();
758 let result = match self.degree {
759 0 => {
760 projection.mapv(|v| normalization * v.max(0.0))
762 }
763 1 => {
764 projection.mapv(|v| if v > 0.0 { normalization * v } else { 0.0 })
766 }
767 2 => {
768 projection.mapv(|v| if v > 0.0 { normalization * v * v } else { 0.0 })
770 }
771 _ => unreachable!("degree validation should prevent this"),
772 };
773
774 Ok(result)
775 }
776}
777
778impl ArcCosineSampler<Trained> {
779 pub fn random_weights(&self) -> Result<&Array2<Float>> {
781 self.random_weights_
782 .as_ref()
783 .ok_or_else(|| SklearsError::InvalidInput("Model not fitted".to_string()))
784 }
785
786 pub fn degree(&self) -> u32 {
788 self.degree
789 }
790}
791
792#[allow(non_snake_case)]
793#[cfg(test)]
794mod tests {
795 use super::*;
796 use scirs2_core::ndarray::array;
797
798 #[test]
799 fn test_rbf_sampler_basic() {
800 let x = array![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0],];
801
802 let rbf = RBFSampler::new(50).gamma(0.1);
803 let fitted = rbf.fit(&x, &()).unwrap();
804 let x_transformed = fitted.transform(&x).unwrap();
805
806 assert_eq!(x_transformed.shape(), &[3, 50]);
807
808 for val in x_transformed.iter() {
810 assert!(val.abs() <= 2.0); }
812 }
813
814 #[test]
815 fn test_rbf_sampler_reproducibility() {
816 let x = array![[1.0, 2.0], [3.0, 4.0],];
817
818 let rbf1 = RBFSampler::new(10).random_state(42);
819 let fitted1 = rbf1.fit(&x, &()).unwrap();
820 let result1 = fitted1.transform(&x).unwrap();
821
822 let rbf2 = RBFSampler::new(10).random_state(42);
823 let fitted2 = rbf2.fit(&x, &()).unwrap();
824 let result2 = fitted2.transform(&x).unwrap();
825
826 for (a, b) in result1.iter().zip(result2.iter()) {
828 assert!((a - b).abs() < 1e-10);
829 }
830 }
831
832 #[test]
833 fn test_rbf_sampler_feature_mismatch() {
834 let x_train = array![[1.0, 2.0], [3.0, 4.0],];
835
836 let x_test = array![
837 [1.0, 2.0, 3.0], ];
839
840 let rbf = RBFSampler::new(10);
841 let fitted = rbf.fit(&x_train, &()).unwrap();
842 let result = fitted.transform(&x_test);
843
844 assert!(result.is_err());
845 }
846
847 #[test]
848 fn test_rbf_sampler_invalid_gamma() {
849 let x = array![[1.0, 2.0]];
850 let rbf = RBFSampler::new(10).gamma(-1.0);
851 let result = rbf.fit(&x, &());
852 assert!(result.is_err());
853 }
854
855 #[test]
856 fn test_rbf_sampler_zero_components() {
857 let x = array![[1.0, 2.0]];
858 let rbf = RBFSampler::new(0);
859 let result = rbf.fit(&x, &());
860 assert!(result.is_err());
861 }
862
863 #[test]
864 fn test_laplacian_sampler_basic() {
865 let x = array![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0],];
866
867 let laplacian = LaplacianSampler::new(50).gamma(0.1);
868 let fitted = laplacian.fit(&x, &()).unwrap();
869 let x_transformed = fitted.transform(&x).unwrap();
870
871 assert_eq!(x_transformed.shape(), &[3, 50]);
872
873 for val in x_transformed.iter() {
875 assert!(val.abs() <= 2.0); }
877 }
878
879 #[test]
880 fn test_laplacian_sampler_reproducibility() {
881 let x = array![[1.0, 2.0], [3.0, 4.0],];
882
883 let laplacian1 = LaplacianSampler::new(10).random_state(42);
884 let fitted1 = laplacian1.fit(&x, &()).unwrap();
885 let result1 = fitted1.transform(&x).unwrap();
886
887 let laplacian2 = LaplacianSampler::new(10).random_state(42);
888 let fitted2 = laplacian2.fit(&x, &()).unwrap();
889 let result2 = fitted2.transform(&x).unwrap();
890
891 for (a, b) in result1.iter().zip(result2.iter()) {
893 assert!((a - b).abs() < 1e-10);
894 }
895 }
896
897 #[test]
898 fn test_laplacian_sampler_feature_mismatch() {
899 let x_train = array![[1.0, 2.0], [3.0, 4.0],];
900
901 let x_test = array![
902 [1.0, 2.0, 3.0], ];
904
905 let laplacian = LaplacianSampler::new(10);
906 let fitted = laplacian.fit(&x_train, &()).unwrap();
907 let result = fitted.transform(&x_test);
908
909 assert!(result.is_err());
910 }
911
912 #[test]
913 fn test_laplacian_sampler_invalid_gamma() {
914 let x = array![[1.0, 2.0]];
915 let laplacian = LaplacianSampler::new(10).gamma(-1.0);
916 let result = laplacian.fit(&x, &());
917 assert!(result.is_err());
918 }
919
920 #[test]
921 fn test_laplacian_sampler_zero_components() {
922 let x = array![[1.0, 2.0]];
923 let laplacian = LaplacianSampler::new(0);
924 let result = laplacian.fit(&x, &());
925 assert!(result.is_err());
926 }
927
928 #[test]
929 fn test_polynomial_sampler_basic() {
930 let x = array![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0],];
931
932 let poly = PolynomialSampler::new(50).degree(3).gamma(1.0).coef0(1.0);
933 let fitted = poly.fit(&x, &()).unwrap();
934 let x_transformed = fitted.transform(&x).unwrap();
935
936 assert_eq!(x_transformed.shape(), &[3, 50]);
937
938 for val in x_transformed.iter() {
940 assert!(val.is_finite());
941 }
942 }
943
944 #[test]
945 fn test_polynomial_sampler_reproducibility() {
946 let x = array![[1.0, 2.0], [3.0, 4.0],];
947
948 let poly1 = PolynomialSampler::new(10).degree(2).random_state(42);
949 let fitted1 = poly1.fit(&x, &()).unwrap();
950 let result1 = fitted1.transform(&x).unwrap();
951
952 let poly2 = PolynomialSampler::new(10).degree(2).random_state(42);
953 let fitted2 = poly2.fit(&x, &()).unwrap();
954 let result2 = fitted2.transform(&x).unwrap();
955
956 for (a, b) in result1.iter().zip(result2.iter()) {
958 assert!((a - b).abs() < 1e-10);
959 }
960 }
961
962 #[test]
963 fn test_polynomial_sampler_feature_mismatch() {
964 let x_train = array![[1.0, 2.0], [3.0, 4.0],];
965
966 let x_test = array![
967 [1.0, 2.0, 3.0], ];
969
970 let poly = PolynomialSampler::new(10);
971 let fitted = poly.fit(&x_train, &()).unwrap();
972 let result = fitted.transform(&x_test);
973
974 assert!(result.is_err());
975 }
976
977 #[test]
978 fn test_polynomial_sampler_invalid_gamma() {
979 let x = array![[1.0, 2.0]];
980 let poly = PolynomialSampler::new(10).gamma(-1.0);
981 let result = poly.fit(&x, &());
982 assert!(result.is_err());
983 }
984
985 #[test]
986 fn test_polynomial_sampler_zero_degree() {
987 let x = array![[1.0, 2.0]];
988 let poly = PolynomialSampler::new(10).degree(0);
989 let result = poly.fit(&x, &());
990 assert!(result.is_err());
991 }
992
993 #[test]
994 fn test_polynomial_sampler_zero_components() {
995 let x = array![[1.0, 2.0]];
996 let poly = PolynomialSampler::new(0);
997 let result = poly.fit(&x, &());
998 assert!(result.is_err());
999 }
1000
1001 #[test]
1002 fn test_polynomial_sampler_different_degrees() {
1003 let x = array![[1.0, 2.0], [3.0, 4.0],];
1004
1005 let poly1 = PolynomialSampler::new(10).degree(1);
1007 let fitted1 = poly1.fit(&x, &()).unwrap();
1008 let result1 = fitted1.transform(&x).unwrap();
1009 assert_eq!(result1.shape(), &[2, 10]);
1010
1011 let poly5 = PolynomialSampler::new(10).degree(5);
1013 let fitted5 = poly5.fit(&x, &()).unwrap();
1014 let result5 = fitted5.transform(&x).unwrap();
1015 assert_eq!(result5.shape(), &[2, 10]);
1016 }
1017
1018 #[test]
1019 fn test_arc_cosine_sampler_basic() {
1020 let x = array![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0],];
1021
1022 let arc_cosine = ArcCosineSampler::new(50).degree(1);
1023 let fitted = arc_cosine.fit(&x, &()).unwrap();
1024 let x_transformed = fitted.transform(&x).unwrap();
1025
1026 assert_eq!(x_transformed.shape(), &[3, 50]);
1027
1028 for val in x_transformed.iter() {
1030 assert!(val >= &0.0);
1031 assert!(val.is_finite());
1032 }
1033 }
1034
1035 #[test]
1036 fn test_arc_cosine_sampler_reproducibility() {
1037 let x = array![[1.0, 2.0], [3.0, 4.0],];
1038
1039 let arc1 = ArcCosineSampler::new(10).degree(1).random_state(42);
1040 let fitted1 = arc1.fit(&x, &()).unwrap();
1041 let result1 = fitted1.transform(&x).unwrap();
1042
1043 let arc2 = ArcCosineSampler::new(10).degree(1).random_state(42);
1044 let fitted2 = arc2.fit(&x, &()).unwrap();
1045 let result2 = fitted2.transform(&x).unwrap();
1046
1047 for (a, b) in result1.iter().zip(result2.iter()) {
1049 assert!((a - b).abs() < 1e-10);
1050 }
1051 }
1052
1053 #[test]
1054 fn test_arc_cosine_sampler_different_degrees() {
1055 let x = array![[1.0, 2.0], [3.0, 4.0],];
1056
1057 let arc0 = ArcCosineSampler::new(10).degree(0);
1059 let fitted0 = arc0.fit(&x, &()).unwrap();
1060 let result0 = fitted0.transform(&x).unwrap();
1061 assert_eq!(result0.shape(), &[2, 10]);
1062
1063 let arc1 = ArcCosineSampler::new(10).degree(1);
1065 let fitted1 = arc1.fit(&x, &()).unwrap();
1066 let result1 = fitted1.transform(&x).unwrap();
1067 assert_eq!(result1.shape(), &[2, 10]);
1068
1069 let arc2 = ArcCosineSampler::new(10).degree(2);
1071 let fitted2 = arc2.fit(&x, &()).unwrap();
1072 let result2 = fitted2.transform(&x).unwrap();
1073 assert_eq!(result2.shape(), &[2, 10]);
1074 }
1075
1076 #[test]
1077 fn test_arc_cosine_sampler_feature_mismatch() {
1078 let x_train = array![[1.0, 2.0], [3.0, 4.0],];
1079
1080 let x_test = array![
1081 [1.0, 2.0, 3.0], ];
1083
1084 let arc_cosine = ArcCosineSampler::new(10);
1085 let fitted = arc_cosine.fit(&x_train, &()).unwrap();
1086 let result = fitted.transform(&x_test);
1087
1088 assert!(result.is_err());
1089 }
1090
1091 #[test]
1092 fn test_arc_cosine_sampler_invalid_degree() {
1093 let x = array![[1.0, 2.0]];
1094 let arc_cosine = ArcCosineSampler::new(10).degree(3);
1095 let result = arc_cosine.fit(&x, &());
1096 assert!(result.is_err());
1097 }
1098
1099 #[test]
1100 fn test_arc_cosine_sampler_zero_components() {
1101 let x = array![[1.0, 2.0]];
1102 let arc_cosine = ArcCosineSampler::new(0);
1103 let result = arc_cosine.fit(&x, &());
1104 assert!(result.is_err());
1105 }
1106}