1use scirs2_core::parallel_ops::{
9 IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator,
10};
11use scirs2_core::Complex64;
12use std::sync::Mutex;
13
14use quantrs2_circuit::builder::{Circuit, Simulator};
15use quantrs2_core::{
16 error::{QuantRS2Error, QuantRS2Result},
17 gate::{multi, single, GateOp},
18 qubit::QubitId,
19 register::Register,
20};
21
22use crate::diagnostics::SimulationDiagnostics;
23use crate::optimized_simd;
24use crate::scirs2_integration::{SciRS2Backend, SciRS2Matrix, SciRS2Vector, BLAS};
25use crate::utils::{flip_bit, gate_vec_to_array2};
26
27#[derive(Debug)]
46pub struct StateVectorSimulator {
47 pub parallel: bool,
49
50 pub noise_model: Option<crate::noise::NoiseModel>,
52
53 pub advanced_noise_model: Option<crate::noise_advanced::AdvancedNoiseModel>,
55
56 buffer_pool: Mutex<BufferPool>,
58
59 pub use_simd: bool,
61
62 pub use_gate_fusion: bool,
64
65 pub diagnostics: Option<SimulationDiagnostics>,
67
68 scirs2_backend: SciRS2Backend,
70
71 current_state: Vec<Complex64>,
79}
80
81impl Clone for StateVectorSimulator {
82 fn clone(&self) -> Self {
83 Self {
84 parallel: self.parallel,
85 noise_model: self.noise_model.clone(),
86 advanced_noise_model: self.advanced_noise_model.clone(),
87 buffer_pool: Mutex::new(BufferPool::new(4, 1024)), use_simd: self.use_simd,
89 use_gate_fusion: self.use_gate_fusion,
90 diagnostics: self
91 .diagnostics
92 .as_ref()
93 .map(|_| SimulationDiagnostics::new()),
94 scirs2_backend: SciRS2Backend::new(),
95 current_state: self.current_state.clone(),
96 }
97 }
98}
99
100#[derive(Debug, Clone)]
102pub struct BufferPool {
103 working_buffers: std::collections::VecDeque<Vec<Complex64>>,
105 max_buffers: usize,
107 target_size: usize,
109}
110
111impl BufferPool {
112 #[must_use]
114 pub fn new(max_buffers: usize, target_size: usize) -> Self {
115 Self {
116 working_buffers: std::collections::VecDeque::with_capacity(max_buffers),
117 max_buffers,
118 target_size,
119 }
120 }
121
122 pub fn get_buffer(&mut self, size: usize) -> Vec<Complex64> {
124 if let Some(mut buffer) = self.working_buffers.pop_front() {
126 if buffer.capacity() >= size {
127 buffer.clear();
128 buffer.resize(size, Complex64::new(0.0, 0.0));
129 return buffer;
130 }
131 }
132
133 let capacity = size.max(self.target_size);
135 let mut buffer = Vec::with_capacity(capacity);
136 buffer.resize(size, Complex64::new(0.0, 0.0));
137 buffer
138 }
139
140 pub fn return_buffer(&mut self, buffer: Vec<Complex64>) {
142 if self.working_buffers.len() < self.max_buffers
143 && buffer.capacity() >= self.target_size / 2
144 {
145 self.working_buffers.push_back(buffer);
146 }
147 }
149
150 pub fn clear(&mut self) {
152 self.working_buffers.clear();
153 }
154}
155
156impl StateVectorSimulator {
157 #[must_use]
159 pub fn new() -> Self {
160 Self {
161 parallel: true,
162 noise_model: None,
163 advanced_noise_model: None,
164 buffer_pool: Mutex::new(BufferPool::new(4, 1024)), use_simd: true,
166 use_gate_fusion: true,
167 diagnostics: None,
168 scirs2_backend: SciRS2Backend::new(),
169 current_state: Vec::new(),
170 }
171 }
172
173 #[must_use]
175 pub fn sequential() -> Self {
176 Self {
177 parallel: false,
178 noise_model: None,
179 advanced_noise_model: None,
180 buffer_pool: Mutex::new(BufferPool::new(2, 512)), use_simd: true,
182 use_gate_fusion: true,
183 diagnostics: None,
184 scirs2_backend: SciRS2Backend::new(),
185 current_state: Vec::new(),
186 }
187 }
188
189 #[must_use]
191 pub fn with_noise(noise_model: crate::noise::NoiseModel) -> Self {
192 Self {
193 parallel: true,
194 noise_model: Some(noise_model),
195 advanced_noise_model: None,
196 buffer_pool: Mutex::new(BufferPool::new(4, 1024)),
197 use_simd: true,
198 use_gate_fusion: true,
199 diagnostics: None,
200 scirs2_backend: SciRS2Backend::new(),
201 current_state: Vec::new(),
202 }
203 }
204
205 #[must_use]
207 pub fn with_advanced_noise(
208 advanced_noise_model: crate::noise_advanced::AdvancedNoiseModel,
209 ) -> Self {
210 Self {
211 parallel: true,
212 noise_model: None,
213 advanced_noise_model: Some(advanced_noise_model),
214 buffer_pool: Mutex::new(BufferPool::new(4, 1024)),
215 use_simd: true,
216 use_gate_fusion: true,
217 diagnostics: None,
218 scirs2_backend: SciRS2Backend::new(),
219 current_state: Vec::new(),
220 }
221 }
222
223 #[must_use]
225 pub fn with_buffer_pool(parallel: bool, max_buffers: usize, target_size: usize) -> Self {
226 Self {
227 parallel,
228 noise_model: None,
229 advanced_noise_model: None,
230 buffer_pool: Mutex::new(BufferPool::new(max_buffers, target_size)),
231 use_simd: true,
232 use_gate_fusion: true,
233 diagnostics: None,
234 scirs2_backend: SciRS2Backend::new(),
235 current_state: Vec::new(),
236 }
237 }
238
239 pub fn set_noise_model(&mut self, noise_model: crate::noise::NoiseModel) -> &mut Self {
241 self.noise_model = Some(noise_model);
242 self.advanced_noise_model = None; self
244 }
245
246 pub fn set_advanced_noise_model(
248 &mut self,
249 advanced_noise_model: crate::noise_advanced::AdvancedNoiseModel,
250 ) -> &mut Self {
251 self.advanced_noise_model = Some(advanced_noise_model);
252 self.noise_model = None; self
254 }
255
256 pub fn remove_noise_model(&mut self) -> &mut Self {
258 self.noise_model = None;
259 self.advanced_noise_model = None;
260 self
261 }
262
263 pub const fn set_simd_enabled(&mut self, enabled: bool) -> &mut Self {
265 self.use_simd = enabled;
266 self
267 }
268
269 pub const fn set_gate_fusion_enabled(&mut self, enabled: bool) -> &mut Self {
271 self.use_gate_fusion = enabled;
272 self
273 }
274
275 pub const fn get_buffer_pool(&self) -> &Mutex<BufferPool> {
277 &self.buffer_pool
278 }
279
280 pub fn enable_diagnostics(&mut self) -> &mut Self {
282 self.diagnostics = Some(SimulationDiagnostics::new());
283 self
284 }
285
286 pub fn disable_diagnostics(&mut self) -> &mut Self {
288 self.diagnostics = None;
289 self
290 }
291
292 pub fn get_diagnostics_report(&self) -> Option<crate::diagnostics::DiagnosticReport> {
294 self.diagnostics
295 .as_ref()
296 .map(super::diagnostics::SimulationDiagnostics::generate_report)
297 }
298
299 #[must_use]
301 pub fn high_performance() -> Self {
302 Self {
303 parallel: true,
304 noise_model: None,
305 advanced_noise_model: None,
306 buffer_pool: Mutex::new(BufferPool::new(8, 2048)), use_simd: true,
308 use_gate_fusion: true,
309 diagnostics: Some(SimulationDiagnostics::new()),
310 scirs2_backend: SciRS2Backend::new(),
311 current_state: Vec::new(),
312 }
313 }
314
315 #[cfg(feature = "advanced_math")]
317 fn apply_dense_matrix_vector(
318 &mut self,
319 matrix: &[Complex64],
320 vector: &[Complex64],
321 result: &mut [Complex64],
322 ) -> QuantRS2Result<()> {
323 if self.scirs2_backend.is_available() && matrix.len() >= 64 && vector.len() >= 8 {
324 use scirs2_core::ndarray::{Array1, Array2};
326
327 let rows = result.len();
328 let cols = vector.len();
329
330 if matrix.len() != rows * cols {
331 return Err(QuantRS2Error::InvalidInput(
332 "Dimension mismatch in matrix application".to_string(),
333 ));
334 }
335
336 let matrix_2d =
338 Array2::from_shape_vec((rows, cols), matrix.to_vec()).map_err(|_| {
339 QuantRS2Error::InvalidInput("Matrix shape conversion failed".to_string())
340 })?;
341 let vector_1d = Array1::from_vec(vector.to_vec());
342
343 let scirs2_matrix = SciRS2Matrix::from_array2(matrix_2d);
345 let scirs2_vector = SciRS2Vector::from_array1(vector_1d);
346
347 let scirs2_result = self
349 .scirs2_backend
350 .matrix_vector_multiply(&scirs2_matrix, &scirs2_vector)
351 .map_err(|_| {
352 QuantRS2Error::ComputationError(
353 "Matrix-vector multiplication failed".to_string(),
354 )
355 })?;
356
357 let result_array = scirs2_result.to_array1().map_err(|_| {
359 QuantRS2Error::ComputationError("Result conversion to array failed".to_string())
360 })?;
361 if let Some(slice) = result_array.as_slice() {
362 result.copy_from_slice(slice);
363 } else {
364 return Err(QuantRS2Error::ComputationError(
365 "Result array is not contiguous".to_string(),
366 ));
367 }
368
369 Ok(())
370 } else {
371 for i in 0..result.len() {
373 result[i] = Complex64::new(0.0, 0.0);
374 for j in 0..vector.len() {
375 result[i] += matrix[i * vector.len() + j] * vector[j];
376 }
377 }
378 Ok(())
379 }
380 }
381
382 #[cfg(not(feature = "advanced_math"))]
384 fn apply_dense_matrix_vector(
385 &self,
386 matrix: &[Complex64],
387 vector: &[Complex64],
388 result: &mut [Complex64],
389 ) -> QuantRS2Result<()> {
390 for i in 0..result.len() {
392 result[i] = Complex64::new(0.0, 0.0);
393 for j in 0..vector.len() {
394 result[i] += matrix[i * vector.len() + j] * vector[j];
395 }
396 }
397 Ok(())
398 }
399
400 fn apply_single_qubit_gate<const N: usize>(
402 &self,
403 state: &mut [Complex64],
404 gate_matrix: &[Complex64],
405 target: QubitId,
406 ) -> QuantRS2Result<()> {
407 let target_idx = target.id() as usize;
408 if target_idx >= N {
409 return Err(QuantRS2Error::InvalidQubitId(target.id()));
410 }
411
412 if self.use_simd && state.len() >= 8 {
414 return self.apply_single_qubit_gate_simd::<N>(state, gate_matrix, target_idx);
415 }
416
417 let m00 = gate_matrix[0];
420 let m01 = gate_matrix[1];
421 let m10 = gate_matrix[2];
422 let m11 = gate_matrix[3];
423
424 if self.parallel {
426 let mut state_copy = self
428 .buffer_pool
429 .lock()
430 .expect("buffer pool lock poisoned")
431 .get_buffer(state.len());
432 state_copy.copy_from_slice(state);
433
434 state.par_iter_mut().enumerate().for_each(|(idx, amp)| {
435 let bit_val = (idx >> target_idx) & 1;
436 let paired_idx = if bit_val == 0 {
437 idx | (1 << target_idx)
438 } else {
439 idx & !(1 << target_idx)
440 };
441
442 let idx0 = if bit_val == 0 { idx } else { paired_idx };
443 let idx1 = if bit_val == 0 { paired_idx } else { idx };
444
445 let val0 = state_copy[idx0];
446 let val1 = state_copy[idx1];
447
448 *amp = if idx == idx0 {
450 m00 * val0 + m01 * val1
451 } else {
452 m10 * val0 + m11 * val1
453 };
454 });
455
456 self.buffer_pool
458 .lock()
459 .expect("buffer pool lock poisoned")
460 .return_buffer(state_copy);
461 } else {
462 let dim = state.len();
464 let mut new_state = self
465 .buffer_pool
466 .lock()
467 .expect("buffer pool lock poisoned")
468 .get_buffer(dim);
469
470 for i in 0..dim {
471 let bit_val = (i >> target_idx) & 1;
472 let paired_idx = flip_bit(i, target_idx);
473
474 if bit_val == 0 {
475 new_state[i] = m00 * state[i] + m01 * state[paired_idx];
476 new_state[paired_idx] = m10 * state[i] + m11 * state[paired_idx];
477 }
478 }
479
480 state.copy_from_slice(&new_state);
481 self.buffer_pool
483 .lock()
484 .expect("buffer pool lock poisoned")
485 .return_buffer(new_state);
486 }
487
488 Ok(())
489 }
490
491 fn apply_single_qubit_gate_simd<const N: usize>(
493 &self,
494 state: &mut [Complex64],
495 gate_matrix: &[Complex64],
496 target_idx: usize,
497 ) -> QuantRS2Result<()> {
498 let dim = state.len();
499 let pairs_per_block = 1 << target_idx;
500 let total_pairs = dim / 2;
501
502 let mut pool = self.buffer_pool.lock().expect("buffer pool lock poisoned");
504 let mut in_amps0 = pool.get_buffer(total_pairs);
505 let mut in_amps1 = pool.get_buffer(total_pairs);
506 let mut out_amps0 = pool.get_buffer(total_pairs);
507 let mut out_amps1 = pool.get_buffer(total_pairs);
508
509 let mut pair_idx = 0;
511 for block in 0..(dim / (pairs_per_block * 2)) {
512 let block_start = block * pairs_per_block * 2;
513
514 for offset in 0..pairs_per_block {
515 let idx0 = block_start + offset;
516 let idx1 = block_start + pairs_per_block + offset;
517
518 in_amps0[pair_idx] = state[idx0];
519 in_amps1[pair_idx] = state[idx1];
520 pair_idx += 1;
521 }
522 }
523
524 let gate_matrix_array: [Complex64; 4] = [
526 gate_matrix[0],
527 gate_matrix[1],
528 gate_matrix[2],
529 gate_matrix[3],
530 ];
531
532 optimized_simd::apply_single_qubit_gate_optimized(
534 &gate_matrix_array,
535 &in_amps0,
536 &in_amps1,
537 &mut out_amps0,
538 &mut out_amps1,
539 );
540
541 pair_idx = 0;
543 for block in 0..(dim / (pairs_per_block * 2)) {
544 let block_start = block * pairs_per_block * 2;
545
546 for offset in 0..pairs_per_block {
547 let idx0 = block_start + offset;
548 let idx1 = block_start + pairs_per_block + offset;
549
550 state[idx0] = out_amps0[pair_idx];
551 state[idx1] = out_amps1[pair_idx];
552 pair_idx += 1;
553 }
554 }
555
556 pool.return_buffer(in_amps0);
558 pool.return_buffer(in_amps1);
559 pool.return_buffer(out_amps0);
560 pool.return_buffer(out_amps1);
561
562 Ok(())
563 }
564
565 fn apply_two_qubit_gate<const N: usize>(
567 &self,
568 state: &mut [Complex64],
569 gate_matrix: &[Complex64],
570 control: QubitId,
571 target: QubitId,
572 ) -> QuantRS2Result<()> {
573 let control_idx = control.id() as usize;
574 let target_idx = target.id() as usize;
575
576 if control_idx >= N || target_idx >= N {
577 return Err(QuantRS2Error::InvalidQubitId(if control_idx >= N {
578 control.id()
579 } else {
580 target.id()
581 }));
582 }
583
584 if control_idx == target_idx {
585 return Err(QuantRS2Error::CircuitValidationFailed(
586 "Control and target qubits must be different".into(),
587 ));
588 }
589
590 let m = gate_matrix; if self.parallel {
595 let mut state_copy = self
597 .buffer_pool
598 .lock()
599 .expect("buffer pool lock poisoned")
600 .get_buffer(state.len());
601 state_copy.copy_from_slice(state);
602
603 state.par_iter_mut().enumerate().for_each(|(idx, amp)| {
604 let idx00 = idx & !(1 << control_idx) & !(1 << target_idx);
605 let idx01 = idx00 | (1 << target_idx);
606 let idx10 = idx00 | (1 << control_idx);
607 let idx11 = idx00 | (1 << control_idx) | (1 << target_idx);
608
609 let val00 = state_copy[idx00];
610 let val01 = state_copy[idx01];
611 let val10 = state_copy[idx10];
612 let val11 = state_copy[idx11];
613
614 *amp = match idx {
616 i if i == idx00 => m[0] * val00 + m[1] * val01 + m[2] * val10 + m[3] * val11,
617 i if i == idx01 => m[4] * val00 + m[5] * val01 + m[6] * val10 + m[7] * val11,
618 i if i == idx10 => m[8] * val00 + m[9] * val01 + m[10] * val10 + m[11] * val11,
619 i if i == idx11 => {
620 m[12] * val00 + m[13] * val01 + m[14] * val10 + m[15] * val11
621 }
622 _ => unreachable!(),
623 };
624 });
625
626 self.buffer_pool
628 .lock()
629 .expect("buffer pool lock poisoned")
630 .return_buffer(state_copy);
631 } else {
632 let dim = state.len();
634 let mut new_state = self
635 .buffer_pool
636 .lock()
637 .expect("buffer pool lock poisoned")
638 .get_buffer(dim);
639
640 #[allow(clippy::needless_range_loop)]
641 for i in 0..dim {
642 let control_bit = (i >> control_idx) & 1;
643 let target_bit = (i >> target_idx) & 1;
644
645 let i00 = i & !(1 << control_idx) & !(1 << target_idx);
647 let i01 = i00 | (1 << target_idx);
648 let i10 = i00 | (1 << control_idx);
649 let i11 = i10 | (1 << target_idx);
650
651 let basis_idx = (control_bit << 1) | target_bit;
652
653 let row_offset = basis_idx * 4;
655 new_state[i] = m[row_offset] * state[i00]
656 + m[row_offset + 1] * state[i01]
657 + m[row_offset + 2] * state[i10]
658 + m[row_offset + 3] * state[i11];
659 }
660
661 state.copy_from_slice(&new_state);
662 self.buffer_pool
664 .lock()
665 .expect("buffer pool lock poisoned")
666 .return_buffer(new_state);
667 }
668
669 Ok(())
670 }
671
672 fn apply_cnot<const N: usize>(
674 &self,
675 state: &mut [Complex64],
676 control: QubitId,
677 target: QubitId,
678 ) -> QuantRS2Result<()> {
679 let control_idx = control.id() as usize;
680 let target_idx = target.id() as usize;
681
682 if control_idx >= N || target_idx >= N {
683 return Err(QuantRS2Error::InvalidQubitId(if control_idx >= N {
684 control.id()
685 } else {
686 target.id()
687 }));
688 }
689
690 if control_idx == target_idx {
691 return Err(QuantRS2Error::CircuitValidationFailed(
692 "Control and target qubits must be different".into(),
693 ));
694 }
695
696 if self.parallel {
698 let mut state_copy = self
699 .buffer_pool
700 .lock()
701 .expect("buffer pool lock poisoned")
702 .get_buffer(state.len());
703 state_copy.copy_from_slice(state);
704
705 state.par_iter_mut().enumerate().for_each(|(i, amp)| {
706 if (i >> control_idx) & 1 == 1 {
707 let flipped = flip_bit(i, target_idx);
708 *amp = state_copy[flipped];
709 }
710 });
711
712 self.buffer_pool
713 .lock()
714 .expect("buffer pool lock poisoned")
715 .return_buffer(state_copy);
716 } else {
717 let dim = state.len();
718 let mut new_state = self
719 .buffer_pool
720 .lock()
721 .expect("buffer pool lock poisoned")
722 .get_buffer(dim);
723
724 for i in 0..dim {
725 if (i >> control_idx) & 1 == 1 {
726 let flipped = flip_bit(i, target_idx);
727 new_state[flipped] = state[i];
728 new_state[i] = state[flipped];
729 } else {
730 new_state[i] = state[i];
731 }
732 }
733
734 state.copy_from_slice(&new_state);
735 self.buffer_pool
736 .lock()
737 .expect("buffer pool lock poisoned")
738 .return_buffer(new_state);
739 }
740
741 Ok(())
742 }
743
744 fn apply_swap<const N: usize>(
746 &self,
747 state: &mut [Complex64],
748 qubit1: QubitId,
749 qubit2: QubitId,
750 ) -> QuantRS2Result<()> {
751 let q1_idx = qubit1.id() as usize;
752 let q2_idx = qubit2.id() as usize;
753
754 if q1_idx >= N || q2_idx >= N {
755 return Err(QuantRS2Error::InvalidQubitId(if q1_idx >= N {
756 qubit1.id()
757 } else {
758 qubit2.id()
759 }));
760 }
761
762 if q1_idx == q2_idx {
763 return Err(QuantRS2Error::CircuitValidationFailed(
764 "Qubits must be different for SWAP gate".into(),
765 ));
766 }
767
768 if self.parallel {
770 let mut state_copy = self
771 .buffer_pool
772 .lock()
773 .expect("buffer pool lock poisoned")
774 .get_buffer(state.len());
775 state_copy.copy_from_slice(state);
776
777 state.par_iter_mut().enumerate().for_each(|(i, amp)| {
778 let bit1 = (i >> q1_idx) & 1;
779 let bit2 = (i >> q2_idx) & 1;
780
781 if bit1 != bit2 {
782 let swapped = flip_bit(flip_bit(i, q1_idx), q2_idx);
783 *amp = state_copy[swapped];
784 }
785 });
786
787 self.buffer_pool
788 .lock()
789 .expect("buffer pool lock poisoned")
790 .return_buffer(state_copy);
791 } else {
792 let dim = state.len();
793 let mut new_state = self
794 .buffer_pool
795 .lock()
796 .expect("buffer pool lock poisoned")
797 .get_buffer(dim);
798
799 for i in 0..dim {
800 let bit1 = (i >> q1_idx) & 1;
801 let bit2 = (i >> q2_idx) & 1;
802
803 if bit1 == bit2 {
804 new_state[i] = state[i];
805 } else {
806 let swapped = flip_bit(flip_bit(i, q1_idx), q2_idx);
807 new_state[swapped] = state[i];
808 new_state[i] = state[swapped];
809 }
810 }
811
812 state.copy_from_slice(&new_state);
813 self.buffer_pool
814 .lock()
815 .expect("buffer pool lock poisoned")
816 .return_buffer(new_state);
817 }
818
819 Ok(())
820 }
821}
822
823impl Default for StateVectorSimulator {
824 fn default() -> Self {
825 Self::new()
826 }
827}
828
829impl<const N: usize> Simulator<N> for StateVectorSimulator {
830 fn run(&self, circuit: &Circuit<N>) -> QuantRS2Result<Register<N>> {
831 let dim = 1 << N;
833 let mut state = vec![Complex64::new(0.0, 0.0); dim];
834 state[0] = Complex64::new(1.0, 0.0);
835
836 for gate in circuit.gates() {
838 match gate.name() {
839 "H" => {
841 if let Some(g) = gate.as_any().downcast_ref::<single::Hadamard>() {
842 let matrix = g.matrix()?;
843 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
844 }
845 }
846 "X" => {
847 if let Some(g) = gate.as_any().downcast_ref::<single::PauliX>() {
848 let matrix = g.matrix()?;
849 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
850 }
851 }
852 "Y" => {
853 if let Some(g) = gate.as_any().downcast_ref::<single::PauliY>() {
854 let matrix = g.matrix()?;
855 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
856 }
857 }
858 "Z" => {
859 if let Some(g) = gate.as_any().downcast_ref::<single::PauliZ>() {
860 let matrix = g.matrix()?;
861 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
862 }
863 }
864 "RX" => {
865 if let Some(g) = gate.as_any().downcast_ref::<single::RotationX>() {
866 let matrix = g.matrix()?;
867 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
868 }
869 }
870 "RY" => {
871 if let Some(g) = gate.as_any().downcast_ref::<single::RotationY>() {
872 let matrix = g.matrix()?;
873 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
874 }
875 }
876 "RZ" => {
877 if let Some(g) = gate.as_any().downcast_ref::<single::RotationZ>() {
878 let matrix = g.matrix()?;
879 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
880 }
881 }
882 "S" => {
883 if let Some(g) = gate.as_any().downcast_ref::<single::Phase>() {
884 let matrix = g.matrix()?;
885 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
886 }
887 }
888 "T" => {
889 if let Some(g) = gate.as_any().downcast_ref::<single::T>() {
890 let matrix = g.matrix()?;
891 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
892 }
893 }
894 "S†" => {
895 if let Some(g) = gate.as_any().downcast_ref::<single::PhaseDagger>() {
896 let matrix = g.matrix()?;
897 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
898 }
899 }
900 "T†" => {
901 if let Some(g) = gate.as_any().downcast_ref::<single::TDagger>() {
902 let matrix = g.matrix()?;
903 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
904 }
905 }
906 "√X" => {
907 if let Some(g) = gate.as_any().downcast_ref::<single::SqrtX>() {
908 let matrix = g.matrix()?;
909 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
910 }
911 }
912 "√X†" => {
913 if let Some(g) = gate.as_any().downcast_ref::<single::SqrtXDagger>() {
914 let matrix = g.matrix()?;
915 self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
916 }
917 }
918
919 "CNOT" => {
921 if let Some(g) = gate.as_any().downcast_ref::<multi::CNOT>() {
922 self.apply_cnot::<N>(&mut state, g.control, g.target)?;
924 }
925 }
926 "CZ" => {
927 if let Some(g) = gate.as_any().downcast_ref::<multi::CZ>() {
928 let matrix = g.matrix()?;
929 self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
930 }
931 }
932 "SWAP" => {
933 if let Some(g) = gate.as_any().downcast_ref::<multi::SWAP>() {
934 self.apply_swap::<N>(&mut state, g.qubit1, g.qubit2)?;
936 }
937 }
938 "CY" => {
939 if let Some(g) = gate.as_any().downcast_ref::<multi::CY>() {
940 let matrix = g.matrix()?;
941 self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
942 }
943 }
944 "CH" => {
945 if let Some(g) = gate.as_any().downcast_ref::<multi::CH>() {
946 let matrix = g.matrix()?;
947 self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
948 }
949 }
950 "CS" => {
951 if let Some(g) = gate.as_any().downcast_ref::<multi::CS>() {
952 let matrix = g.matrix()?;
953 self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
954 }
955 }
956 "CRX" => {
957 if let Some(g) = gate.as_any().downcast_ref::<multi::CRX>() {
958 let matrix = g.matrix()?;
959 self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
960 }
961 }
962 "CRY" => {
963 if let Some(g) = gate.as_any().downcast_ref::<multi::CRY>() {
964 let matrix = g.matrix()?;
965 self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
966 }
967 }
968 "CRZ" => {
969 if let Some(g) = gate.as_any().downcast_ref::<multi::CRZ>() {
970 let matrix = g.matrix()?;
971 self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
972 }
973 }
974
975 "Toffoli" => {
977 if let Some(toffoli_gate) = gate.as_any().downcast_ref::<multi::Toffoli>() {
978 let control1 = toffoli_gate.control1;
979 let control2 = toffoli_gate.control2;
980 let target = toffoli_gate.target;
981 self.apply_toffoli_to_state::<N>(&mut state, control1, control2, target)?;
982 }
983 }
984 "Fredkin" => {
985 if let Some(fredkin_gate) = gate.as_any().downcast_ref::<multi::Fredkin>() {
986 let control = fredkin_gate.control;
987 let target1 = fredkin_gate.target1;
988 let target2 = fredkin_gate.target2;
989 self.apply_fredkin_to_state::<N>(&mut state, control, target1, target2)?;
990 }
991 }
992
993 _ => {
994 return Err(QuantRS2Error::UnsupportedOperation(format!(
995 "Gate {} not supported",
996 gate.name()
997 )));
998 }
999 }
1000
1001 if let Some(ref noise_model) = self.noise_model {
1003 if noise_model.per_gate {
1004 noise_model.apply_to_statevector(&mut state)?;
1005 }
1006 }
1007
1008 if let Some(ref advanced_noise_model) = self.advanced_noise_model {
1010 if advanced_noise_model.per_gate {
1011 advanced_noise_model.apply_to_statevector(&mut state)?;
1012 }
1013 }
1014 }
1015
1016 if let Some(ref noise_model) = self.noise_model {
1018 if !noise_model.per_gate {
1019 noise_model.apply_to_statevector(&mut state)?;
1020 }
1021 }
1022
1023 if let Some(ref advanced_noise_model) = self.advanced_noise_model {
1025 if !advanced_noise_model.per_gate {
1026 advanced_noise_model.apply_to_statevector(&mut state)?;
1027 }
1028 }
1029
1030 Register::<N>::with_amplitudes(state)
1032 }
1033}
1034
1035impl StateVectorSimulator {
1036 fn state_num_qubits(&self) -> QuantRS2Result<usize> {
1040 let len = self.current_state.len();
1041 if len == 0 || !len.is_power_of_two() {
1042 return Err(QuantRS2Error::InvalidInput(
1043 "Quantum state has not been initialised; call initialize_state first".to_string(),
1044 ));
1045 }
1046 Ok(len.trailing_zeros() as usize)
1047 }
1048
1049 fn check_qubit(&self, qubit: usize) -> QuantRS2Result<()> {
1051 let n = self.state_num_qubits()?;
1052 if qubit >= n {
1053 return Err(QuantRS2Error::InvalidQubitId(qubit as u32));
1054 }
1055 Ok(())
1056 }
1057
1058 pub fn initialize_state(&mut self, num_qubits: usize) -> QuantRS2Result<()> {
1063 if num_qubits == 0 {
1064 return Err(QuantRS2Error::InvalidInput(
1065 "Number of qubits must be at least 1".to_string(),
1066 ));
1067 }
1068 if num_qubits >= usize::BITS as usize {
1069 return Err(QuantRS2Error::InvalidInput(format!(
1070 "Number of qubits {num_qubits} is too large to address"
1071 )));
1072 }
1073 let dim = 1usize << num_qubits;
1074 let mut state = vec![Complex64::new(0.0, 0.0); dim];
1075 state[0] = Complex64::new(1.0, 0.0);
1076 self.current_state = state;
1077 Ok(())
1078 }
1079
1080 pub fn get_state(&self) -> Vec<Complex64> {
1082 self.current_state.clone()
1083 }
1084
1085 pub fn get_state_mut(&mut self) -> Vec<Complex64> {
1090 self.current_state.clone()
1091 }
1092
1093 pub fn set_state(&mut self, state: Vec<Complex64>) -> QuantRS2Result<()> {
1098 if state.is_empty() || !state.len().is_power_of_two() {
1099 return Err(QuantRS2Error::InvalidInput(
1100 "State vector length must be a non-zero power of two".to_string(),
1101 ));
1102 }
1103 self.current_state = state;
1104 Ok(())
1105 }
1106
1107 pub fn apply_interface_circuit(
1113 &mut self,
1114 circuit: &crate::circuit_interfaces::InterfaceCircuit,
1115 ) -> QuantRS2Result<()> {
1116 let expected_dim = 1usize << circuit.num_qubits;
1117 if self.current_state.len() != expected_dim {
1118 self.initialize_state(circuit.num_qubits)?;
1119 }
1120 let mut state = std::mem::take(&mut self.current_state);
1121 let result = (|| {
1122 for gate in &circuit.gates {
1123 apply_interface_gate_to_state(&mut state, gate, circuit.num_qubits)?;
1124 }
1125 Ok(())
1126 })();
1127 self.current_state = state;
1128 result
1129 }
1130
1131 pub fn apply_h(&mut self, qubit: usize) -> QuantRS2Result<()> {
1133 self.check_qubit(qubit)?;
1134 let inv_sqrt2 = 1.0 / std::f64::consts::SQRT_2;
1135 let matrix = [
1136 Complex64::new(inv_sqrt2, 0.0),
1137 Complex64::new(inv_sqrt2, 0.0),
1138 Complex64::new(inv_sqrt2, 0.0),
1139 Complex64::new(-inv_sqrt2, 0.0),
1140 ];
1141 apply_single_qubit_inplace(&mut self.current_state, &matrix, qubit);
1142 Ok(())
1143 }
1144
1145 pub fn apply_x(&mut self, qubit: usize) -> QuantRS2Result<()> {
1147 self.check_qubit(qubit)?;
1148 let matrix = [
1149 Complex64::new(0.0, 0.0),
1150 Complex64::new(1.0, 0.0),
1151 Complex64::new(1.0, 0.0),
1152 Complex64::new(0.0, 0.0),
1153 ];
1154 apply_single_qubit_inplace(&mut self.current_state, &matrix, qubit);
1155 Ok(())
1156 }
1157
1158 pub fn apply_z_public(&mut self, qubit: usize) -> QuantRS2Result<()> {
1160 self.check_qubit(qubit)?;
1161 let matrix = [
1162 Complex64::new(1.0, 0.0),
1163 Complex64::new(0.0, 0.0),
1164 Complex64::new(0.0, 0.0),
1165 Complex64::new(-1.0, 0.0),
1166 ];
1167 apply_single_qubit_inplace(&mut self.current_state, &matrix, qubit);
1168 Ok(())
1169 }
1170
1171 pub fn apply_cnot_public(&mut self, control: usize, target: usize) -> QuantRS2Result<()> {
1173 self.check_qubit(control)?;
1174 self.check_qubit(target)?;
1175 if control == target {
1176 return Err(QuantRS2Error::InvalidInput(
1177 "CNOT control and target must differ".to_string(),
1178 ));
1179 }
1180 let control_mask = 1usize << control;
1181 let target_mask = 1usize << target;
1182 for i in 0..self.current_state.len() {
1183 if (i & control_mask) != 0 && (i & target_mask) == 0 {
1184 self.current_state.swap(i, i | target_mask);
1185 }
1186 }
1187 Ok(())
1188 }
1189
1190 fn apply_toffoli_to_state<const N: usize>(
1192 &self,
1193 state: &mut [Complex64],
1194 control1: QubitId,
1195 control2: QubitId,
1196 target: QubitId,
1197 ) -> QuantRS2Result<()> {
1198 let control1_idx = control1.id() as usize;
1199 let control2_idx = control2.id() as usize;
1200 let target_idx = target.id() as usize;
1201
1202 if control1_idx >= N || control2_idx >= N || target_idx >= N {
1203 return Err(QuantRS2Error::InvalidQubitId(if control1_idx >= N {
1204 control1.id()
1205 } else if control2_idx >= N {
1206 control2.id()
1207 } else {
1208 target.id()
1209 }));
1210 }
1211
1212 if self.parallel {
1214 let mut state_copy = self
1215 .buffer_pool
1216 .lock()
1217 .expect("buffer pool lock poisoned")
1218 .get_buffer(state.len());
1219 state_copy.copy_from_slice(state);
1220
1221 state.par_iter_mut().enumerate().for_each(|(i, amp)| {
1222 let control1_bit = (i >> control1_idx) & 1;
1223 let control2_bit = (i >> control2_idx) & 1;
1224
1225 if control1_bit == 1 && control2_bit == 1 {
1226 let flipped = flip_bit(i, target_idx);
1227 *amp = state_copy[flipped];
1228 }
1229 });
1230
1231 self.buffer_pool
1232 .lock()
1233 .expect("buffer pool lock poisoned")
1234 .return_buffer(state_copy);
1235 } else {
1236 let mut new_state = self
1237 .buffer_pool
1238 .lock()
1239 .expect("buffer pool lock poisoned")
1240 .get_buffer(state.len());
1241 new_state.copy_from_slice(state);
1242
1243 for i in 0..state.len() {
1244 let control1_bit = (i >> control1_idx) & 1;
1245 let control2_bit = (i >> control2_idx) & 1;
1246
1247 if control1_bit == 1 && control2_bit == 1 {
1248 let flipped = flip_bit(i, target_idx);
1249 new_state[flipped] = state[i];
1250 new_state[i] = state[flipped];
1251 }
1252 }
1253
1254 state.copy_from_slice(&new_state);
1255 self.buffer_pool
1256 .lock()
1257 .expect("buffer pool lock poisoned")
1258 .return_buffer(new_state);
1259 }
1260
1261 Ok(())
1262 }
1263
1264 fn apply_fredkin_to_state<const N: usize>(
1266 &self,
1267 state: &mut [Complex64],
1268 control: QubitId,
1269 target1: QubitId,
1270 target2: QubitId,
1271 ) -> QuantRS2Result<()> {
1272 let control_idx = control.id() as usize;
1273 let target1_idx = target1.id() as usize;
1274 let target2_idx = target2.id() as usize;
1275
1276 if control_idx >= N || target1_idx >= N || target2_idx >= N {
1277 return Err(QuantRS2Error::InvalidQubitId(if control_idx >= N {
1278 control.id()
1279 } else if target1_idx >= N {
1280 target1.id()
1281 } else {
1282 target2.id()
1283 }));
1284 }
1285
1286 if self.parallel {
1288 let mut state_copy = self
1289 .buffer_pool
1290 .lock()
1291 .expect("buffer pool lock poisoned")
1292 .get_buffer(state.len());
1293 state_copy.copy_from_slice(state);
1294
1295 state.par_iter_mut().enumerate().for_each(|(i, amp)| {
1296 let control_bit = (i >> control_idx) & 1;
1297 let target1_bit = (i >> target1_idx) & 1;
1298 let target2_bit = (i >> target2_idx) & 1;
1299
1300 if control_bit == 1 && target1_bit != target2_bit {
1301 let swapped = flip_bit(flip_bit(i, target1_idx), target2_idx);
1302 *amp = state_copy[swapped];
1303 }
1304 });
1305
1306 self.buffer_pool
1307 .lock()
1308 .expect("buffer pool lock poisoned")
1309 .return_buffer(state_copy);
1310 } else {
1311 let mut new_state = self
1312 .buffer_pool
1313 .lock()
1314 .expect("buffer pool lock poisoned")
1315 .get_buffer(state.len());
1316 new_state.copy_from_slice(state);
1317
1318 for i in 0..state.len() {
1319 let control_bit = (i >> control_idx) & 1;
1320 let target1_bit = (i >> target1_idx) & 1;
1321 let target2_bit = (i >> target2_idx) & 1;
1322
1323 if control_bit == 1 && target1_bit != target2_bit {
1324 let swapped = flip_bit(flip_bit(i, target1_idx), target2_idx);
1325 new_state[swapped] = state[i];
1326 new_state[i] = state[swapped];
1327 }
1328 }
1329
1330 state.copy_from_slice(&new_state);
1331 self.buffer_pool
1332 .lock()
1333 .expect("buffer pool lock poisoned")
1334 .return_buffer(new_state);
1335 }
1336
1337 Ok(())
1338 }
1339
1340 pub fn apply_toffoli(
1344 &mut self,
1345 control1: QubitId,
1346 control2: QubitId,
1347 target: QubitId,
1348 ) -> QuantRS2Result<()> {
1349 let c1 = control1.id() as usize;
1350 let c2 = control2.id() as usize;
1351 let t = target.id() as usize;
1352 self.check_qubit(c1)?;
1353 self.check_qubit(c2)?;
1354 self.check_qubit(t)?;
1355 if c1 == c2 || c1 == t || c2 == t {
1356 return Err(QuantRS2Error::InvalidInput(
1357 "Toffoli controls and target must be distinct".to_string(),
1358 ));
1359 }
1360 let c1_mask = 1usize << c1;
1361 let c2_mask = 1usize << c2;
1362 let t_mask = 1usize << t;
1363 for i in 0..self.current_state.len() {
1364 if (i & c1_mask) != 0 && (i & c2_mask) != 0 && (i & t_mask) == 0 {
1365 self.current_state.swap(i, i | t_mask);
1366 }
1367 }
1368 Ok(())
1369 }
1370
1371 pub fn apply_fredkin(
1375 &mut self,
1376 control: QubitId,
1377 target1: QubitId,
1378 target2: QubitId,
1379 ) -> QuantRS2Result<()> {
1380 let c = control.id() as usize;
1381 let t1 = target1.id() as usize;
1382 let t2 = target2.id() as usize;
1383 self.check_qubit(c)?;
1384 self.check_qubit(t1)?;
1385 self.check_qubit(t2)?;
1386 if c == t1 || c == t2 || t1 == t2 {
1387 return Err(QuantRS2Error::InvalidInput(
1388 "Fredkin control and targets must be distinct".to_string(),
1389 ));
1390 }
1391 let c_mask = 1usize << c;
1392 let t1_mask = 1usize << t1;
1393 let t2_mask = 1usize << t2;
1394 for i in 0..self.current_state.len() {
1395 if (i & c_mask) != 0 && (i & t1_mask) == 0 && (i & t2_mask) != 0 {
1398 let partner = (i | t1_mask) & !t2_mask;
1399 self.current_state.swap(i, partner);
1400 }
1401 }
1402 Ok(())
1403 }
1404}
1405
1406fn apply_single_qubit_inplace(state: &mut [Complex64], matrix: &[Complex64; 4], target: usize) {
1411 let target_mask = 1usize << target;
1412 for i in 0..state.len() {
1413 if (i & target_mask) == 0 {
1414 let j = i | target_mask;
1415 let a = state[i];
1416 let b = state[j];
1417 state[i] = matrix[0] * a + matrix[1] * b;
1418 state[j] = matrix[2] * a + matrix[3] * b;
1419 }
1420 }
1421}
1422
1423fn apply_multi_qubit_inplace(
1428 state: &mut [Complex64],
1429 matrix: &scirs2_core::ndarray::Array2<Complex64>,
1430 qubits: &[usize],
1431) -> QuantRS2Result<()> {
1432 let k = qubits.len();
1433 let gate_dim = 1usize << k;
1434 if matrix.nrows() != gate_dim || matrix.ncols() != gate_dim {
1435 return Err(QuantRS2Error::InvalidInput(format!(
1436 "Gate matrix dimension {}x{} does not match {} qubit(s)",
1437 matrix.nrows(),
1438 matrix.ncols(),
1439 k
1440 )));
1441 }
1442 let mut combined_mask = 0usize;
1443 for &q in qubits {
1444 combined_mask |= 1usize << q;
1445 }
1446
1447 let mut indices = vec![0usize; gate_dim];
1448 let mut inputs = vec![Complex64::new(0.0, 0.0); gate_dim];
1449 for base in 0..state.len() {
1450 if base & combined_mask != 0 {
1454 continue;
1455 }
1456 for (g, (idx_slot, in_slot)) in indices.iter_mut().zip(inputs.iter_mut()).enumerate() {
1457 let mut idx = base;
1458 for (b, &q) in qubits.iter().enumerate() {
1459 if (g >> (k - 1 - b)) & 1 == 1 {
1460 idx |= 1usize << q;
1461 }
1462 }
1463 *idx_slot = idx;
1464 *in_slot = state[idx];
1465 }
1466 for row in 0..gate_dim {
1467 let mut acc = Complex64::new(0.0, 0.0);
1468 for (col, &inp) in inputs.iter().enumerate() {
1469 acc += matrix[[row, col]] * inp;
1470 }
1471 state[indices[row]] = acc;
1472 }
1473 }
1474 Ok(())
1475}
1476
1477fn apply_interface_gate_to_state(
1486 state: &mut [Complex64],
1487 gate: &crate::circuit_interfaces::InterfaceGate,
1488 num_qubits: usize,
1489) -> QuantRS2Result<()> {
1490 use crate::circuit_interfaces::InterfaceGateType;
1491
1492 for &q in &gate.qubits {
1493 if q >= num_qubits {
1494 return Err(QuantRS2Error::InvalidQubitId(q as u32));
1495 }
1496 }
1497
1498 let inv_sqrt2 = 1.0 / std::f64::consts::SQRT_2;
1499 match &gate.gate_type {
1500 InterfaceGateType::Identity => Ok(()),
1501 InterfaceGateType::PauliX | InterfaceGateType::X => {
1502 let m = [
1503 Complex64::new(0.0, 0.0),
1504 Complex64::new(1.0, 0.0),
1505 Complex64::new(1.0, 0.0),
1506 Complex64::new(0.0, 0.0),
1507 ];
1508 apply_single_qubit_inplace(state, &m, gate.qubits[0]);
1509 Ok(())
1510 }
1511 InterfaceGateType::Hadamard | InterfaceGateType::H => {
1512 let m = [
1513 Complex64::new(inv_sqrt2, 0.0),
1514 Complex64::new(inv_sqrt2, 0.0),
1515 Complex64::new(inv_sqrt2, 0.0),
1516 Complex64::new(-inv_sqrt2, 0.0),
1517 ];
1518 apply_single_qubit_inplace(state, &m, gate.qubits[0]);
1519 Ok(())
1520 }
1521 InterfaceGateType::Measure | InterfaceGateType::Reset => {
1522 Err(QuantRS2Error::UnsupportedOperation(format!(
1523 "State-vector apply_interface_circuit does not support non-unitary '{:?}'",
1524 gate.gate_type
1525 )))
1526 }
1527 _ => {
1528 let matrix = gate
1529 .unitary_matrix()
1530 .map_err(|e| QuantRS2Error::InvalidInput(e.to_string()))?;
1531 if gate.qubits.len() == 1 {
1532 let flat = [
1533 matrix[[0, 0]],
1534 matrix[[0, 1]],
1535 matrix[[1, 0]],
1536 matrix[[1, 1]],
1537 ];
1538 apply_single_qubit_inplace(state, &flat, gate.qubits[0]);
1539 Ok(())
1540 } else {
1541 apply_multi_qubit_inplace(state, &matrix, &gate.qubits)
1542 }
1543 }
1544 }
1545}