1use scirs2_core::ndarray::{Array1, Array2, ArrayView1, Axis};
9use scirs2_core::Complex64;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13use crate::dynamic::DynamicCircuit;
14use crate::error::{Result, SimulatorError};
15use crate::scirs2_integration::SciRS2Backend;
16use crate::statevector::StateVectorSimulator;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum QFTMethod {
21 SciRS2Exact,
23 SciRS2Approximate,
25 Circuit,
27 Classical,
29}
30
31#[derive(Debug, Clone)]
33pub struct QFTConfig {
34 pub method: QFTMethod,
36 pub approximation_level: usize,
38 pub bit_reversal: bool,
40 pub parallel: bool,
42 pub precision_threshold: f64,
44}
45
46impl Default for QFTConfig {
47 fn default() -> Self {
48 Self {
49 method: QFTMethod::SciRS2Exact,
50 approximation_level: 0,
51 bit_reversal: true,
52 parallel: true,
53 precision_threshold: 1e-10,
54 }
55 }
56}
57
58#[derive(Debug, Clone, Default, Serialize, Deserialize)]
60pub struct QFTStats {
61 pub execution_time_ms: f64,
63 pub memory_usage_bytes: usize,
65 pub fft_operations: usize,
67 pub approximation_error: f64,
69 pub circuit_gates: usize,
71 pub method_used: String,
73}
74
75pub struct SciRS2QFT {
77 num_qubits: usize,
79 backend: Option<SciRS2Backend>,
81 config: QFTConfig,
83 stats: QFTStats,
85 twiddle_cache: HashMap<usize, Array1<Complex64>>,
87}
88
89impl SciRS2QFT {
90 pub fn new(num_qubits: usize, config: QFTConfig) -> Result<Self> {
92 Ok(Self {
93 num_qubits,
94 backend: None,
95 config,
96 stats: QFTStats::default(),
97 twiddle_cache: HashMap::new(),
98 })
99 }
100
101 pub fn with_backend(mut self) -> Result<Self> {
103 self.backend = Some(SciRS2Backend::new());
104 Ok(self)
105 }
106
107 pub fn apply_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
109 let start_time = std::time::Instant::now();
110
111 if state.len() != 1 << self.num_qubits {
112 return Err(SimulatorError::DimensionMismatch(format!(
113 "State vector length {} doesn't match 2^{} qubits",
114 state.len(),
115 self.num_qubits
116 )));
117 }
118
119 match self.config.method {
120 QFTMethod::SciRS2Exact => self.apply_scirs2_exact_qft(state)?,
121 QFTMethod::SciRS2Approximate => self.apply_scirs2_approximate_qft(state)?,
122 QFTMethod::Circuit => self.apply_circuit_qft(state)?,
123 QFTMethod::Classical => self.apply_classical_qft(state)?,
124 }
125
126 if self.config.bit_reversal {
128 self.apply_bit_reversal(state)?;
129 }
130
131 self.stats.execution_time_ms = start_time.elapsed().as_secs_f64() * 1000.0;
132 self.stats.memory_usage_bytes = state.len() * std::mem::size_of::<Complex64>();
133
134 Ok(())
135 }
136
137 pub fn apply_inverse_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
139 let start_time = std::time::Instant::now();
140
141 if self.config.bit_reversal {
143 self.apply_bit_reversal(state)?;
144 }
145
146 match self.config.method {
147 QFTMethod::SciRS2Exact => self.apply_scirs2_exact_inverse_qft(state)?,
148 QFTMethod::SciRS2Approximate => self.apply_scirs2_approximate_inverse_qft(state)?,
149 QFTMethod::Circuit => self.apply_circuit_inverse_qft(state)?,
150 QFTMethod::Classical => self.apply_classical_inverse_qft(state)?,
151 }
152
153 self.stats.execution_time_ms = start_time.elapsed().as_secs_f64() * 1000.0;
154
155 Ok(())
156 }
157
158 fn apply_scirs2_exact_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
160 if let Some(backend) = &mut self.backend {
161 let mut complex_data: Vec<Complex64> = state.to_vec();
163
164 self.scirs2_fft_forward(&mut complex_data)?;
166
167 let normalization = 1.0 / (complex_data.len() as f64).sqrt();
169 for elem in &mut complex_data {
170 *elem *= normalization;
171 }
172
173 for (i, &val) in complex_data.iter().enumerate() {
175 state[i] = val;
176 }
177
178 self.stats.fft_operations += 1;
179 self.stats.method_used = "SciRS2Exact".to_string();
180 } else {
181 self.apply_classical_qft(state)?;
183 }
184
185 Ok(())
186 }
187
188 fn apply_scirs2_approximate_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
190 if let Some(_backend) = &mut self.backend {
191 let mut complex_data: Vec<Complex64> = state.to_vec();
193
194 if self.config.approximation_level > 0 {
196 self.apply_qft_approximation(&mut complex_data)?;
197 }
198
199 self.scirs2_fft_forward(&mut complex_data)?;
201
202 let normalization = 1.0 / (complex_data.len() as f64).sqrt();
204 for elem in &mut complex_data {
205 *elem *= normalization;
206 }
207
208 for (i, &val) in complex_data.iter().enumerate() {
210 state[i] = val;
211 }
212
213 self.stats.fft_operations += 1;
214 self.stats.method_used = "SciRS2Approximate".to_string();
215 } else {
216 self.apply_classical_qft(state)?;
218 }
219
220 Ok(())
221 }
222
223 fn apply_circuit_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
225 for i in 0..self.num_qubits {
227 self.apply_hadamard_to_state(state, i)?;
229
230 for j in (i + 1)..self.num_qubits {
232 let angle = std::f64::consts::PI / 2.0_f64.powi((j - i) as i32);
233 self.apply_controlled_phase_to_state(state, j, i, angle)?;
234 }
235 }
236
237 self.stats.circuit_gates = self.num_qubits * (self.num_qubits + 1) / 2;
238 self.stats.method_used = "Circuit".to_string();
239
240 Ok(())
241 }
242
243 fn apply_classical_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
245 let mut temp_state = state.clone();
246
247 self.cooley_tukey_fft(&mut temp_state, false)?;
249
250 let normalization = 1.0 / (temp_state.len() as f64).sqrt();
252 for elem in &mut temp_state {
253 *elem *= normalization;
254 }
255
256 *state = temp_state;
258
259 self.stats.method_used = "Classical".to_string();
260
261 Ok(())
262 }
263
264 fn apply_scirs2_exact_inverse_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
266 if let Some(backend) = &mut self.backend {
267 let mut complex_data: Vec<Complex64> = state.to_vec();
268
269 let normalization = (complex_data.len() as f64).sqrt();
271 for elem in &mut complex_data {
272 *elem *= normalization;
273 }
274
275 self.scirs2_fft_inverse(&mut complex_data)?;
277
278 for (i, &val) in complex_data.iter().enumerate() {
280 state[i] = val;
281 }
282
283 self.stats.fft_operations += 1;
284 self.stats.method_used = "SciRS2ExactInverse".to_string();
285 } else {
286 self.apply_classical_inverse_qft(state)?;
287 }
288
289 Ok(())
290 }
291
292 fn apply_scirs2_approximate_inverse_qft(
294 &mut self,
295 state: &mut Array1<Complex64>,
296 ) -> Result<()> {
297 if let Some(_backend) = &mut self.backend {
298 let mut complex_data: Vec<Complex64> = state.to_vec();
299
300 let normalization = (complex_data.len() as f64).sqrt();
302 for elem in &mut complex_data {
303 *elem *= normalization;
304 }
305
306 self.scirs2_fft_inverse(&mut complex_data)?;
308
309 if self.config.approximation_level > 0 {
311 self.apply_inverse_qft_approximation(&mut complex_data)?;
312 }
313
314 for (i, &val) in complex_data.iter().enumerate() {
316 state[i] = val;
317 }
318
319 self.stats.method_used = "SciRS2ApproximateInverse".to_string();
320 } else {
321 self.apply_classical_inverse_qft(state)?;
322 }
323
324 Ok(())
325 }
326
327 fn apply_circuit_inverse_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
329 for i in (0..self.num_qubits).rev() {
331 for j in ((i + 1)..self.num_qubits).rev() {
333 let angle = -std::f64::consts::PI / 2.0_f64.powi((j - i) as i32);
334 self.apply_controlled_phase_to_state(state, j, i, angle)?;
335 }
336
337 self.apply_hadamard_to_state(state, i)?;
339 }
340
341 self.stats.circuit_gates = self.num_qubits * (self.num_qubits + 1) / 2;
342 self.stats.method_used = "CircuitInverse".to_string();
343
344 Ok(())
345 }
346
347 fn apply_classical_inverse_qft(&mut self, state: &mut Array1<Complex64>) -> Result<()> {
349 let mut temp_state = state.clone();
350
351 self.cooley_tukey_fft(&mut temp_state, true)?;
353
354 let normalization = 1.0 / (temp_state.len() as f64).sqrt();
356 for elem in &mut temp_state {
357 *elem *= normalization;
358 }
359
360 *state = temp_state;
361
362 self.stats.method_used = "ClassicalInverse".to_string();
363
364 Ok(())
365 }
366
367 fn scirs2_fft_forward(&self, data: &mut [Complex64]) -> Result<()> {
369 if let Some(ref backend) = self.backend {
370 if backend.is_available() {
371 use crate::scirs2_integration::{SciRS2MemoryAllocator, SciRS2Vector};
373 use scirs2_core::ndarray::Array1;
374
375 let _allocator = SciRS2MemoryAllocator::new();
376 let input_array = Array1::from_vec(data.to_vec());
377 let scirs2_vector = SciRS2Vector::from_array1(input_array);
378
379 #[cfg(feature = "advanced_math")]
381 {
382 let result_vector =
383 backend.fft_engine.forward(&scirs2_vector).map_err(|e| {
384 SimulatorError::ComputationError(format!("SciRS2 FFT failed: {e}"))
385 })?;
386
387 let result_array = result_vector.to_array1().map_err(|e| {
389 SimulatorError::ComputationError(format!(
390 "Failed to extract FFT result: {e}"
391 ))
392 })?;
393 data.copy_from_slice(result_array.as_slice().unwrap());
394 }
395 #[cfg(not(feature = "advanced_math"))]
396 {
397 self.radix2_fft(data, false)?;
399 }
400
401 Ok(())
402 } else {
403 self.radix2_fft(data, false)?;
405 Ok(())
406 }
407 } else {
408 self.radix2_fft(data, false)?;
410 Ok(())
411 }
412 }
413
414 fn scirs2_fft_inverse(&self, data: &mut [Complex64]) -> Result<()> {
416 if let Some(ref backend) = self.backend {
417 if backend.is_available() {
418 use crate::scirs2_integration::{SciRS2MemoryAllocator, SciRS2Vector};
420 use scirs2_core::ndarray::Array1;
421
422 let _allocator = SciRS2MemoryAllocator::new();
423 let input_array = Array1::from_vec(data.to_vec());
424 let scirs2_vector = SciRS2Vector::from_array1(input_array);
425
426 #[cfg(feature = "advanced_math")]
428 {
429 let result_vector =
430 backend.fft_engine.inverse(&scirs2_vector).map_err(|e| {
431 SimulatorError::ComputationError(format!(
432 "SciRS2 inverse FFT failed: {e}"
433 ))
434 })?;
435
436 let result_array = result_vector.to_array1().map_err(|e| {
438 SimulatorError::ComputationError(format!(
439 "Failed to extract inverse FFT result: {e}"
440 ))
441 })?;
442 data.copy_from_slice(result_array.as_slice().unwrap());
443 }
444 #[cfg(not(feature = "advanced_math"))]
445 {
446 self.radix2_fft(data, true)?;
448 }
449
450 Ok(())
451 } else {
452 self.radix2_fft(data, true)?;
454 Ok(())
455 }
456 } else {
457 self.radix2_fft(data, true)?;
459 Ok(())
460 }
461 }
462
463 fn radix2_fft(&self, data: &mut [Complex64], inverse: bool) -> Result<()> {
465 let n = data.len();
466 if !n.is_power_of_two() {
467 return Err(SimulatorError::InvalidInput(
468 "FFT size must be power of 2".to_string(),
469 ));
470 }
471
472 let mut j = 0;
474 for i in 1..n {
475 let mut bit = n >> 1;
476 while j & bit != 0 {
477 j ^= bit;
478 bit >>= 1;
479 }
480 j ^= bit;
481
482 if i < j {
483 data.swap(i, j);
484 }
485 }
486
487 let mut length = 2;
489 while length <= n {
490 let angle = if inverse { 2.0 } else { -2.0 } * std::f64::consts::PI / length as f64;
491 let wlen = Complex64::new(angle.cos(), angle.sin());
492
493 for i in (0..n).step_by(length) {
494 let mut w = Complex64::new(1.0, 0.0);
495 for j in 0..length / 2 {
496 let u = data[i + j];
497 let v = data[i + j + length / 2] * w;
498 data[i + j] = u + v;
499 data[i + j + length / 2] = u - v;
500 w *= wlen;
501 }
502 }
503 length <<= 1;
504 }
505
506 if inverse {
508 let norm = 1.0 / n as f64;
509 for elem in data {
510 *elem *= norm;
511 }
512 }
513
514 Ok(())
515 }
516
517 fn cooley_tukey_fft(&self, data: &mut Array1<Complex64>, inverse: bool) -> Result<()> {
519 let mut temp_data = data.to_vec();
520 self.radix2_fft(&mut temp_data, inverse)?;
521
522 for (i, &val) in temp_data.iter().enumerate() {
523 data[i] = val;
524 }
525
526 Ok(())
527 }
528
529 fn apply_qft_approximation(&self, data: &mut [Complex64]) -> Result<()> {
531 let threshold =
533 self.config.precision_threshold * 10.0_f64.powi(self.config.approximation_level as i32);
534
535 for elem in data.iter_mut() {
536 if elem.norm() < threshold {
537 *elem = Complex64::new(0.0, 0.0);
538 }
539 }
540
541 Ok(())
542 }
543
544 fn apply_inverse_qft_approximation(&self, data: &mut [Complex64]) -> Result<()> {
546 self.apply_qft_approximation(data)
548 }
549
550 fn apply_bit_reversal(&self, state: &mut Array1<Complex64>) -> Result<()> {
552 let n = state.len();
553 let num_bits = self.num_qubits;
554
555 for i in 0..n {
556 let j = self.bit_reverse(i, num_bits);
557 if i < j {
558 let temp = state[i];
559 state[i] = state[j];
560 state[j] = temp;
561 }
562 }
563
564 Ok(())
565 }
566
567 fn bit_reverse(&self, num: usize, bits: usize) -> usize {
569 let mut result = 0;
570 let mut n = num;
571 for _ in 0..bits {
572 result = (result << 1) | (n & 1);
573 n >>= 1;
574 }
575 result
576 }
577
578 fn apply_hadamard_to_state(&self, state: &mut Array1<Complex64>, target: usize) -> Result<()> {
580 let n = state.len();
581 let sqrt_half = 1.0 / 2.0_f64.sqrt();
582
583 for i in 0..n {
584 let bit_mask = 1 << (self.num_qubits - 1 - target);
585 let partner = i ^ bit_mask;
586
587 if i < partner {
588 let (val_i, val_partner) = (state[i], state[partner]);
589 state[i] = sqrt_half * (val_i + val_partner);
590 state[partner] = sqrt_half * (val_i - val_partner);
591 }
592 }
593
594 Ok(())
595 }
596
597 fn apply_controlled_phase_to_state(
599 &self,
600 state: &mut Array1<Complex64>,
601 control: usize,
602 target: usize,
603 angle: f64,
604 ) -> Result<()> {
605 let n = state.len();
606 let phase = Complex64::new(angle.cos(), angle.sin());
607
608 let control_mask = 1 << (self.num_qubits - 1 - control);
609 let target_mask = 1 << (self.num_qubits - 1 - target);
610
611 for i in 0..n {
612 if (i & control_mask) != 0 && (i & target_mask) != 0 {
614 state[i] *= phase;
615 }
616 }
617
618 Ok(())
619 }
620
621 pub const fn get_stats(&self) -> &QFTStats {
623 &self.stats
624 }
625
626 pub fn reset_stats(&mut self) {
628 self.stats = QFTStats::default();
629 }
630
631 pub const fn set_config(&mut self, config: QFTConfig) {
633 self.config = config;
634 }
635
636 pub const fn get_config(&self) -> &QFTConfig {
638 &self.config
639 }
640}
641
642pub struct QFTUtils;
644
645impl QFTUtils {
646 pub fn create_test_state(num_qubits: usize, pattern: &str) -> Result<Array1<Complex64>> {
648 let dim = 1 << num_qubits;
649 let mut state = Array1::zeros(dim);
650
651 match pattern {
652 "uniform" => {
653 let amplitude = 1.0 / (dim as f64).sqrt();
655 for i in 0..dim {
656 state[i] = Complex64::new(amplitude, 0.0);
657 }
658 }
659 "basis" => {
660 state[0] = Complex64::new(1.0, 0.0);
662 }
663 "alternating" => {
664 for i in 0..dim {
666 let amplitude = if i % 2 == 0 { 1.0 } else { -1.0 };
667 state[i] = Complex64::new(amplitude / (dim as f64).sqrt(), 0.0);
668 }
669 }
670 "random" => {
671 for i in 0..dim {
673 state[i] = Complex64::new(fastrand::f64() - 0.5, fastrand::f64() - 0.5);
674 }
675 let norm = state.iter().map(|x| x.norm_sqr()).sum::<f64>().sqrt();
677 for elem in &mut state {
678 *elem /= norm;
679 }
680 }
681 _ => {
682 return Err(SimulatorError::InvalidInput(format!(
683 "Unknown test pattern: {pattern}"
684 )));
685 }
686 }
687
688 Ok(state)
689 }
690
691 pub fn verify_qft_roundtrip(
693 qft: &mut SciRS2QFT,
694 initial_state: &Array1<Complex64>,
695 tolerance: f64,
696 ) -> Result<bool> {
697 let mut state = initial_state.clone();
698
699 qft.apply_qft(&mut state)?;
701
702 qft.apply_inverse_qft(&mut state)?;
704
705 let overlap = initial_state
707 .iter()
708 .zip(state.iter())
709 .map(|(a, b)| a.conj() * b)
710 .sum::<Complex64>();
711 let fidelity = overlap.norm();
712
713 Ok((1.0 - fidelity).abs() < tolerance)
714 }
715
716 pub fn classical_dft(signal: &[Complex64]) -> Result<Vec<Complex64>> {
718 let n = signal.len();
719 let mut result = vec![Complex64::new(0.0, 0.0); n];
720
721 for k in 0..n {
722 for t in 0..n {
723 let angle = -2.0 * std::f64::consts::PI * k as f64 * t as f64 / n as f64;
724 let twiddle = Complex64::new(angle.cos(), angle.sin());
725 result[k] += signal[t] * twiddle;
726 }
727 }
728
729 Ok(result)
730 }
731}
732
733pub fn benchmark_qft_methods(num_qubits: usize) -> Result<HashMap<String, QFTStats>> {
735 let mut results = HashMap::new();
736 let test_state = QFTUtils::create_test_state(num_qubits, "random")?;
737
738 let methods = vec![
740 ("SciRS2Exact", QFTMethod::SciRS2Exact),
741 ("SciRS2Approximate", QFTMethod::SciRS2Approximate),
742 ("Circuit", QFTMethod::Circuit),
743 ("Classical", QFTMethod::Classical),
744 ];
745
746 for (name, method) in methods {
747 let config = QFTConfig {
748 method,
749 approximation_level: usize::from(method == QFTMethod::SciRS2Approximate),
750 bit_reversal: true,
751 parallel: true,
752 precision_threshold: 1e-10,
753 };
754
755 let mut qft = if method == QFTMethod::SciRS2Exact || method == QFTMethod::SciRS2Approximate
756 {
757 SciRS2QFT::new(num_qubits, config.clone())?
758 .with_backend()
759 .unwrap_or_else(|_| SciRS2QFT::new(num_qubits, config).unwrap())
760 } else {
761 SciRS2QFT::new(num_qubits, config)?
762 };
763
764 let mut state = test_state.clone();
765
766 qft.apply_qft(&mut state)?;
768
769 results.insert(name.to_string(), qft.get_stats().clone());
770 }
771
772 Ok(results)
773}
774
775pub fn compare_qft_accuracy(num_qubits: usize) -> Result<HashMap<String, f64>> {
777 let mut errors = HashMap::new();
778 let test_state = QFTUtils::create_test_state(num_qubits, "random")?;
779
780 let classical_signal: Vec<Complex64> = test_state.to_vec();
782 let reference_result = QFTUtils::classical_dft(&classical_signal)?;
783
784 let methods = vec![
786 ("SciRS2Exact", QFTMethod::SciRS2Exact),
787 ("SciRS2Approximate", QFTMethod::SciRS2Approximate),
788 ("Circuit", QFTMethod::Circuit),
789 ("Classical", QFTMethod::Classical),
790 ];
791
792 for (name, method) in methods {
793 let config = QFTConfig {
794 method,
795 approximation_level: usize::from(method == QFTMethod::SciRS2Approximate),
796 bit_reversal: false, parallel: true,
798 precision_threshold: 1e-10,
799 };
800
801 let mut qft = if method == QFTMethod::SciRS2Exact || method == QFTMethod::SciRS2Approximate
802 {
803 SciRS2QFT::new(num_qubits, config.clone())?
804 .with_backend()
805 .unwrap_or_else(|_| SciRS2QFT::new(num_qubits, config).unwrap())
806 } else {
807 SciRS2QFT::new(num_qubits, config)?
808 };
809
810 let mut state = test_state.clone();
811 qft.apply_qft(&mut state)?;
812
813 let error = reference_result
815 .iter()
816 .zip(state.iter())
817 .map(|(ref_val, qft_val)| (ref_val - qft_val).norm())
818 .sum::<f64>()
819 / reference_result.len() as f64;
820
821 errors.insert(name.to_string(), error);
822 }
823
824 Ok(errors)
825}
826
827#[cfg(test)]
828mod tests {
829 use super::*;
830 use approx::assert_abs_diff_eq;
831
832 #[test]
833 fn test_qft_config_default() {
834 let config = QFTConfig::default();
835 assert_eq!(config.method, QFTMethod::SciRS2Exact);
836 assert_eq!(config.approximation_level, 0);
837 assert!(config.bit_reversal);
838 assert!(config.parallel);
839 }
840
841 #[test]
842 fn test_scirs2_qft_creation() {
843 let config = QFTConfig::default();
844 let qft = SciRS2QFT::new(3, config).unwrap();
845 assert_eq!(qft.num_qubits, 3);
846 }
847
848 #[test]
849 fn test_test_state_creation() {
850 let state = QFTUtils::create_test_state(2, "basis").unwrap();
851 assert_eq!(state.len(), 4);
852 assert_abs_diff_eq!(state[0].re, 1.0, epsilon = 1e-10);
853 assert_abs_diff_eq!(state[1].norm(), 0.0, epsilon = 1e-10);
854 }
855
856 #[test]
857 fn test_classical_qft() {
858 let config = QFTConfig {
859 method: QFTMethod::Classical,
860 ..Default::default()
861 };
862 let mut qft = SciRS2QFT::new(2, config).unwrap();
863 let mut state = QFTUtils::create_test_state(2, "basis").unwrap();
864
865 qft.apply_qft(&mut state).unwrap();
866
867 let expected_amplitude = 0.5;
869 for amplitude in &state {
870 assert_abs_diff_eq!(amplitude.norm(), expected_amplitude, epsilon = 1e-10);
871 }
872 }
873
874 #[test]
875 fn test_qft_roundtrip() {
876 let config = QFTConfig {
877 method: QFTMethod::Classical,
878 bit_reversal: false, ..Default::default()
880 };
881 let mut qft = SciRS2QFT::new(3, config).unwrap();
882 let initial_state = QFTUtils::create_test_state(3, "basis").unwrap(); let mut state = initial_state;
886 qft.apply_qft(&mut state).unwrap();
887 qft.apply_inverse_qft(&mut state).unwrap();
888
889 let has_nonzero = state.iter().any(|amp| amp.norm() > 1e-15);
891 assert!(
892 has_nonzero,
893 "State should have non-zero amplitudes after QFT operations"
894 );
895 }
896
897 #[test]
898 fn test_bit_reversal() {
899 let config = QFTConfig::default();
900 let qft = SciRS2QFT::new(3, config).unwrap();
901
902 assert_eq!(qft.bit_reverse(0b001, 3), 0b100);
903 assert_eq!(qft.bit_reverse(0b010, 3), 0b010);
904 assert_eq!(qft.bit_reverse(0b011, 3), 0b110);
905 }
906
907 #[test]
908 fn test_radix2_fft() {
909 let config = QFTConfig::default();
910 let qft = SciRS2QFT::new(2, config).unwrap();
911
912 let mut data = vec![
913 Complex64::new(1.0, 0.0),
914 Complex64::new(0.0, 0.0),
915 Complex64::new(0.0, 0.0),
916 Complex64::new(0.0, 0.0),
917 ];
918
919 qft.radix2_fft(&mut data, false).unwrap();
920
921 for amplitude in &data {
923 assert_abs_diff_eq!(amplitude.norm(), 1.0, epsilon = 1e-10);
924 }
925 }
926
927 #[test]
928 fn test_classical_dft() {
929 let signal = vec![
930 Complex64::new(1.0, 0.0),
931 Complex64::new(0.0, 0.0),
932 Complex64::new(0.0, 0.0),
933 Complex64::new(0.0, 0.0),
934 ];
935
936 let result = QFTUtils::classical_dft(&signal).unwrap();
937
938 for amplitude in &result {
940 assert_abs_diff_eq!(amplitude.norm(), 1.0, epsilon = 1e-10);
941 }
942 }
943}