use super::*;
use std::f64::consts::PI;
#[allow(dead_code)]
fn create_sparse_signal(n: usize, frequencies: &[(usize, f64)]) -> Vec<f64> {
let mut signal = vec![0.0; n];
for i in 0..n {
let t = 2.0 * PI * (i as f64) / (n as f64);
for &(freq, amp) in frequencies {
signal[i] += amp * (freq as f64 * t).sin();
}
}
signal
}
#[test]
#[allow(dead_code)]
fn test_sparse_fft_basic() {
let n = 256;
let frequencies = vec![(3, 1.0), (7, 0.5), (15, 0.25)];
let signal = create_sparse_signal(n, &frequencies);
let result = sparse_fft(&signal, 6, None, None).expect("Operation failed");
assert_eq!(result.values.len(), 6);
}
#[test]
#[allow(dead_code)]
fn test_sparsity_estimation() {
let n = 256;
let frequencies = vec![(3, 1.0), (7, 0.5), (15, 0.25)];
let signal = create_sparse_signal(n, &frequencies);
let config = config::SparseFFTConfig {
estimation_method: config::SparsityEstimationMethod::Threshold,
threshold: 0.1,
..config::SparseFFTConfig::default()
};
let mut processor = algorithms::SparseFFT::new(config);
let estimated_k = processor
.estimate_sparsity(&signal)
.expect("Operation failed");
assert!(estimated_k >= 4 && estimated_k <= 8);
}
#[test]
#[allow(dead_code)]
fn test_frequency_pruning() {
let n = 256;
let frequencies = vec![(3, 1.0), (7, 0.5), (15, 0.25)];
let signal = create_sparse_signal(n, &frequencies);
let config = config::SparseFFTConfig {
estimation_method: config::SparsityEstimationMethod::FrequencyPruning,
algorithm: config::SparseFFTAlgorithm::FrequencyPruning,
pruning_sensitivity: 2.0,
..config::SparseFFTConfig::default()
};
let mut processor = algorithms::SparseFFT::new(config);
let result = processor.sparse_fft(&signal).expect("Operation failed");
assert!(!result.values.is_empty());
let result2 = frequency_pruning_sparse_fft(&signal, 2.0).expect("Operation failed");
assert!(!result2.values.is_empty());
}
#[test]
#[allow(dead_code)]
fn test_spectral_flatness() {
let n = 256;
let frequencies = vec![(3, 1.0), (7, 0.5), (15, 0.25)];
let signal = create_sparse_signal(n, &frequencies);
let mut noisy_signal = signal.clone();
for i in 0..n {
noisy_signal[i] += 0.1 * (i as f64 / n as f64 - 0.5);
}
let config = config::SparseFFTConfig {
estimation_method: config::SparsityEstimationMethod::SpectralFlatness,
algorithm: config::SparseFFTAlgorithm::SpectralFlatness,
flatness_threshold: 0.5,
window_size: 16,
..config::SparseFFTConfig::default()
};
let mut processor = algorithms::SparseFFT::new(config);
let result = processor
.sparse_fft(&noisy_signal)
.expect("Operation failed");
assert!(!result.values.is_empty());
let result2 = spectral_flatness_sparse_fft(&noisy_signal, 0.5, 16).expect("Operation failed");
assert!(!result2.values.is_empty());
}
#[test]
#[allow(dead_code)]
fn test_windowing_functions() {
let signal = vec![1.0, 2.0, 3.0, 4.0];
let result = windowing::apply_window(&signal, config::WindowFunction::Hann, 14.0)
.expect("Operation failed");
assert_eq!(result.len(), 4);
assert!(result[0].re.abs() < 1e-10);
assert!(result[3].re.abs() < 1e-10);
let result = windowing::apply_window(&signal, config::WindowFunction::Hamming, 14.0)
.expect("Operation failed");
assert_eq!(result.len(), 4);
assert!(result[0].re > 0.0);
assert!(result[3].re > 0.0);
let result = windowing::apply_window(&signal, config::WindowFunction::None, 14.0)
.expect("Operation failed");
assert_eq!(result.len(), 4);
assert_eq!(result[0].re, 1.0);
assert_eq!(result[1].re, 2.0);
}
#[test]
#[allow(dead_code)]
fn test_reconstruction() {
let n = 64;
let frequencies = vec![(3, 1.0), (7, 0.5)];
let signal = create_sparse_signal(n, &frequencies);
let sparse_result = sparse_fft(&signal, 4, None, None).expect("Operation failed");
let spectrum =
reconstruction::reconstruct_spectrum(&sparse_result, n).expect("Operation failed");
assert_eq!(spectrum.len(), n);
let reconstructed =
reconstruction::reconstruct_time_domain(&sparse_result, n).expect("Operation failed");
assert_eq!(reconstructed.len(), n);
let high_res = reconstruction::reconstruct_high_resolution(&sparse_result, n, 2 * n)
.expect("Operation failed");
assert_eq!(high_res.len(), 2 * n);
}
#[test]
#[allow(dead_code)]
fn test_adaptive_sparse_fft() {
let n = 128;
let frequencies = vec![(5, 1.0), (10, 0.5), (20, 0.25)];
let signal = create_sparse_signal(n, &frequencies);
let result = adaptive_sparse_fft(&signal, 0.1).expect("Operation failed");
assert!(!result.values.is_empty());
assert!(result.estimated_sparsity > 0);
}
#[test]
#[allow(dead_code)]
fn test_algorithm_variants() {
let n = 64;
let frequencies = vec![(3, 1.0), (7, 0.5)];
let signal = create_sparse_signal(n, &frequencies);
let algorithms = vec![
config::SparseFFTAlgorithm::Sublinear,
config::SparseFFTAlgorithm::CompressedSensing,
config::SparseFFTAlgorithm::Iterative,
config::SparseFFTAlgorithm::Deterministic,
];
for algorithm in algorithms {
let result = sparse_fft(&signal, 4, Some(algorithm), None).expect("Operation failed");
assert_eq!(result.algorithm, algorithm);
assert!(!result.values.is_empty());
assert!(!result.indices.is_empty());
assert_eq!(result.values.len(), result.indices.len());
}
}
#[test]
#[allow(dead_code)]
fn test_performance_measurement() {
let n = 64;
let frequencies = vec![(3, 1.0), (7, 0.5)];
let signal = create_sparse_signal(n, &frequencies);
let result = sparse_fft(&signal, 4, None, None).expect("Operation failed");
assert!(result.computation_time.as_nanos() > 0);
}
#[test]
#[allow(dead_code)]
fn test_edge_cases() {
let empty_signal: Vec<f64> = vec![];
let result = sparse_fft(&empty_signal, 1, None, None);
assert!(result.is_err());
let single_sample = vec![1.0];
let result = sparse_fft(&single_sample, 1, None, None).expect("Operation failed");
assert_eq!(result.values.len(), 1);
let small_signal = vec![1.0, 2.0];
let result = sparse_fft(&small_signal, 10, None, None).expect("Operation failed");
assert!(result.values.len() <= small_signal.len());
}
#[test]
#[allow(dead_code)]
fn test_sparsity_estimation_methods() {
let n = 64;
let frequencies = vec![(3, 1.0), (7, 0.5)];
let signal = create_sparse_signal(n, &frequencies);
let estimated =
estimation::estimate_sparsity_threshold(&signal, 0.1).expect("Operation failed");
assert!(estimated > 0);
let estimated =
estimation::estimate_sparsity_adaptive(&signal, 0.25, 10).expect("Operation failed");
assert!(estimated > 0);
let estimated =
estimation::estimate_sparsity_frequency_pruning(&signal, 2.0).expect("Operation failed");
assert!(estimated > 0);
let estimated =
estimation::estimate_sparsity_spectral_flatness(&signal, 0.3, 8).expect("Operation failed");
assert!(estimated > 0);
}
#[test]
#[allow(dead_code)]
fn test_configuration() {
let config = config::SparseFFTConfig::default();
assert_eq!(config.sparsity, 10);
assert_eq!(config.threshold, 0.01);
assert_eq!(config.max_signal_size, 1024);
let custom_config = config::SparseFFTConfig {
sparsity: 5,
threshold: 0.05,
max_signal_size: 512,
..config::SparseFFTConfig::default()
};
assert_eq!(custom_config.sparsity, 5);
assert_eq!(custom_config.threshold, 0.05);
assert_eq!(custom_config.max_signal_size, 512);
}
#[test]
#[allow(dead_code)]
fn test_signal_size_limit() {
let n = 2048;
let frequencies = vec![(10, 1.0)];
let signal = create_sparse_signal(n, &frequencies);
let config = config::SparseFFTConfig {
max_signal_size: 64,
..config::SparseFFTConfig::default()
};
let mut processor = algorithms::SparseFFT::new(config);
let result = processor.sparse_fft(&signal).expect("Operation failed");
assert!(!result.values.is_empty());
}
#[test]
#[allow(dead_code)]
fn test_complex_input_conversion() {
let complex_val = scirs2_core::numeric::Complex64::new(1.0, 2.0);
assert_eq!(config::try_as_complex(complex_val), Some(complex_val));
let complex32_val = scirs2_core::numeric::Complex32::new(1.0f32, 2.0f32);
assert_eq!(
config::try_as_complex(complex32_val),
Some(scirs2_core::numeric::Complex64::new(1.0, 2.0))
);
}
#[test]
#[allow(dead_code)]
fn test_filtered_reconstruction() {
let n = 64;
let frequencies = vec![(3, 1.0), (7, 0.5), (15, 0.25)];
let signal = create_sparse_signal(n, &frequencies);
let sparse_result = sparse_fft(&signal, 6, None, None).expect("Operation failed");
let low_pass = |freq_idx: usize, n: usize| -> f64 {
if freq_idx <= n / 8 || freq_idx >= 7 * n / 8 {
1.0
} else {
0.0
}
};
let filtered = reconstruction::reconstruct_filtered(&sparse_result, n, low_pass)
.expect("Operation failed");
assert_eq!(filtered.len(), n);
}
#[test]
#[allow(dead_code)]
fn test_multidimensional_placeholders() {
let signal_2d = vec![vec![1.0, 2.0], vec![3.0, 4.0]];
let result = sparse_fft2(&signal_2d, 2, None);
assert!(result.is_err());
let signal_1d = vec![1.0, 2.0, 3.0, 4.0];
let shape = vec![2, 2];
let result = sparse_fftn(&signal_1d, &shape, 2, None);
assert!(result.is_err()); }