Skip to main content

quantrs2_sim/
statevector.rs

1//! State-vector quantum circuit simulator.
2//!
3//! [`StateVectorSimulator`] stores the full 2^N complex amplitude vector and
4//! applies unitary gates via direct matrix-vector products.  It is the default
5//! exact simulator in QuantRS2 and supports up to ~30 qubits on a typical
6//! workstation.
7
8use 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/// A state vector simulator for quantum circuits.
28///
29/// This simulator implements the state vector approach, where the full quantum
30/// state is represented as a complex vector of dimension 2^N for N qubits.
31///
32/// # Examples
33///
34/// ```rust
35/// use quantrs2_sim::statevector::StateVectorSimulator;
36/// use quantrs2_circuit::builder::Circuit;
37/// use quantrs2_circuit::builder::Simulator;
38///
39/// let mut circ: Circuit<2> = Circuit::new();
40/// circ.h(0).expect("h").cnot(0, 1).expect("cnot");
41/// let sim = StateVectorSimulator::new();
42/// let result = sim.run(&circ).expect("simulation failed");
43/// assert_eq!(result.num_qubits(), 2);
44/// ```
45#[derive(Debug)]
46pub struct StateVectorSimulator {
47    /// Use parallel execution
48    pub parallel: bool,
49
50    /// Basic noise model (if any)
51    pub noise_model: Option<crate::noise::NoiseModel>,
52
53    /// Advanced noise model (if any)
54    pub advanced_noise_model: Option<crate::noise_advanced::AdvancedNoiseModel>,
55
56    /// Optimized buffer pool for memory reuse (thread-safe)
57    buffer_pool: Mutex<BufferPool>,
58
59    /// Enable SIMD optimizations for gate operations
60    pub use_simd: bool,
61
62    /// Enable gate fusion optimization
63    pub use_gate_fusion: bool,
64
65    /// Diagnostics system for monitoring and error handling
66    pub diagnostics: Option<SimulationDiagnostics>,
67
68    /// `SciRS2` backend for optimized linear algebra operations
69    scirs2_backend: SciRS2Backend,
70}
71
72impl Clone for StateVectorSimulator {
73    fn clone(&self) -> Self {
74        Self {
75            parallel: self.parallel,
76            noise_model: self.noise_model.clone(),
77            advanced_noise_model: self.advanced_noise_model.clone(),
78            buffer_pool: Mutex::new(BufferPool::new(4, 1024)), // Create new buffer pool
79            use_simd: self.use_simd,
80            use_gate_fusion: self.use_gate_fusion,
81            diagnostics: self
82                .diagnostics
83                .as_ref()
84                .map(|_| SimulationDiagnostics::new()),
85            scirs2_backend: SciRS2Backend::new(),
86        }
87    }
88}
89
90/// Memory pool for efficient state vector operations
91#[derive(Debug, Clone)]
92pub struct BufferPool {
93    /// Pre-allocated working buffers
94    working_buffers: std::collections::VecDeque<Vec<Complex64>>,
95    /// Maximum number of cached buffers
96    max_buffers: usize,
97    /// Target buffer size for efficient reuse
98    target_size: usize,
99}
100
101impl BufferPool {
102    /// Create new buffer pool
103    #[must_use]
104    pub fn new(max_buffers: usize, target_size: usize) -> Self {
105        Self {
106            working_buffers: std::collections::VecDeque::with_capacity(max_buffers),
107            max_buffers,
108            target_size,
109        }
110    }
111
112    /// Get a buffer from pool or allocate new one
113    pub fn get_buffer(&mut self, size: usize) -> Vec<Complex64> {
114        // Try to reuse existing buffer
115        if let Some(mut buffer) = self.working_buffers.pop_front() {
116            if buffer.capacity() >= size {
117                buffer.clear();
118                buffer.resize(size, Complex64::new(0.0, 0.0));
119                return buffer;
120            }
121        }
122
123        // Allocate new buffer with extra capacity for growth
124        let capacity = size.max(self.target_size);
125        let mut buffer = Vec::with_capacity(capacity);
126        buffer.resize(size, Complex64::new(0.0, 0.0));
127        buffer
128    }
129
130    /// Return buffer to pool
131    pub fn return_buffer(&mut self, buffer: Vec<Complex64>) {
132        if self.working_buffers.len() < self.max_buffers
133            && buffer.capacity() >= self.target_size / 2
134        {
135            self.working_buffers.push_back(buffer);
136        }
137        // Otherwise let buffer be dropped and deallocated
138    }
139
140    /// Clear all cached buffers
141    pub fn clear(&mut self) {
142        self.working_buffers.clear();
143    }
144}
145
146impl StateVectorSimulator {
147    /// Create a new state vector simulator with default settings
148    #[must_use]
149    pub fn new() -> Self {
150        Self {
151            parallel: true,
152            noise_model: None,
153            advanced_noise_model: None,
154            buffer_pool: Mutex::new(BufferPool::new(4, 1024)), // Default: 4 buffers, 1K size target
155            use_simd: true,
156            use_gate_fusion: true,
157            diagnostics: None,
158            scirs2_backend: SciRS2Backend::new(),
159        }
160    }
161
162    /// Create a new state vector simulator with parallel execution disabled
163    #[must_use]
164    pub fn sequential() -> Self {
165        Self {
166            parallel: false,
167            noise_model: None,
168            advanced_noise_model: None,
169            buffer_pool: Mutex::new(BufferPool::new(2, 512)), // Smaller pool for sequential
170            use_simd: true,
171            use_gate_fusion: true,
172            diagnostics: None,
173            scirs2_backend: SciRS2Backend::new(),
174        }
175    }
176
177    /// Create a new state vector simulator with a basic noise model
178    #[must_use]
179    pub fn with_noise(noise_model: crate::noise::NoiseModel) -> Self {
180        Self {
181            parallel: true,
182            noise_model: Some(noise_model),
183            advanced_noise_model: None,
184            buffer_pool: Mutex::new(BufferPool::new(4, 1024)),
185            use_simd: true,
186            use_gate_fusion: true,
187            diagnostics: None,
188            scirs2_backend: SciRS2Backend::new(),
189        }
190    }
191
192    /// Create a new state vector simulator with an advanced noise model
193    #[must_use]
194    pub fn with_advanced_noise(
195        advanced_noise_model: crate::noise_advanced::AdvancedNoiseModel,
196    ) -> Self {
197        Self {
198            parallel: true,
199            noise_model: None,
200            advanced_noise_model: Some(advanced_noise_model),
201            buffer_pool: Mutex::new(BufferPool::new(4, 1024)),
202            use_simd: true,
203            use_gate_fusion: true,
204            diagnostics: None,
205            scirs2_backend: SciRS2Backend::new(),
206        }
207    }
208
209    /// Create simulator with custom buffer pool configuration
210    #[must_use]
211    pub fn with_buffer_pool(parallel: bool, max_buffers: usize, target_size: usize) -> Self {
212        Self {
213            parallel,
214            noise_model: None,
215            advanced_noise_model: None,
216            buffer_pool: Mutex::new(BufferPool::new(max_buffers, target_size)),
217            use_simd: true,
218            use_gate_fusion: true,
219            diagnostics: None,
220            scirs2_backend: SciRS2Backend::new(),
221        }
222    }
223
224    /// Set the basic noise model
225    pub fn set_noise_model(&mut self, noise_model: crate::noise::NoiseModel) -> &mut Self {
226        self.noise_model = Some(noise_model);
227        self.advanced_noise_model = None; // Remove advanced model if it exists
228        self
229    }
230
231    /// Set the advanced noise model
232    pub fn set_advanced_noise_model(
233        &mut self,
234        advanced_noise_model: crate::noise_advanced::AdvancedNoiseModel,
235    ) -> &mut Self {
236        self.advanced_noise_model = Some(advanced_noise_model);
237        self.noise_model = None; // Remove basic model if it exists
238        self
239    }
240
241    /// Remove all noise models
242    pub fn remove_noise_model(&mut self) -> &mut Self {
243        self.noise_model = None;
244        self.advanced_noise_model = None;
245        self
246    }
247
248    /// Enable or disable SIMD optimizations
249    pub const fn set_simd_enabled(&mut self, enabled: bool) -> &mut Self {
250        self.use_simd = enabled;
251        self
252    }
253
254    /// Enable or disable gate fusion optimization
255    pub const fn set_gate_fusion_enabled(&mut self, enabled: bool) -> &mut Self {
256        self.use_gate_fusion = enabled;
257        self
258    }
259
260    /// Get access to buffer pool for testing purposes
261    pub const fn get_buffer_pool(&self) -> &Mutex<BufferPool> {
262        &self.buffer_pool
263    }
264
265    /// Enable diagnostics and monitoring
266    pub fn enable_diagnostics(&mut self) -> &mut Self {
267        self.diagnostics = Some(SimulationDiagnostics::new());
268        self
269    }
270
271    /// Disable diagnostics and monitoring
272    pub fn disable_diagnostics(&mut self) -> &mut Self {
273        self.diagnostics = None;
274        self
275    }
276
277    /// Get diagnostics report if diagnostics are enabled
278    pub fn get_diagnostics_report(&self) -> Option<crate::diagnostics::DiagnosticReport> {
279        self.diagnostics
280            .as_ref()
281            .map(super::diagnostics::SimulationDiagnostics::generate_report)
282    }
283
284    /// Create a high-performance configuration
285    #[must_use]
286    pub fn high_performance() -> Self {
287        Self {
288            parallel: true,
289            noise_model: None,
290            advanced_noise_model: None,
291            buffer_pool: Mutex::new(BufferPool::new(8, 2048)), // Larger pool for high performance
292            use_simd: true,
293            use_gate_fusion: true,
294            diagnostics: Some(SimulationDiagnostics::new()),
295            scirs2_backend: SciRS2Backend::new(),
296        }
297    }
298
299    /// Apply a dense matrix-vector multiplication using SciRS2 when available
300    #[cfg(feature = "advanced_math")]
301    fn apply_dense_matrix_vector(
302        &mut self,
303        matrix: &[Complex64],
304        vector: &[Complex64],
305        result: &mut [Complex64],
306    ) -> QuantRS2Result<()> {
307        if self.scirs2_backend.is_available() && matrix.len() >= 64 && vector.len() >= 8 {
308            // Use SciRS2 for larger operations where the overhead is worthwhile
309            use scirs2_core::ndarray::{Array1, Array2};
310
311            let rows = result.len();
312            let cols = vector.len();
313
314            if matrix.len() != rows * cols {
315                return Err(QuantRS2Error::InvalidInput(
316                    "Dimension mismatch in matrix application".to_string(),
317                ));
318            }
319
320            // Convert to ndarray format
321            let matrix_2d =
322                Array2::from_shape_vec((rows, cols), matrix.to_vec()).map_err(|_| {
323                    QuantRS2Error::InvalidInput("Matrix shape conversion failed".to_string())
324                })?;
325            let vector_1d = Array1::from_vec(vector.to_vec());
326
327            // Convert to SciRS2 format
328            let scirs2_matrix = SciRS2Matrix::from_array2(matrix_2d);
329            let scirs2_vector = SciRS2Vector::from_array1(vector_1d);
330
331            // Perform optimized matrix-vector multiplication
332            let scirs2_result = self
333                .scirs2_backend
334                .matrix_vector_multiply(&scirs2_matrix, &scirs2_vector)
335                .map_err(|_| {
336                    QuantRS2Error::ComputationError(
337                        "Matrix-vector multiplication failed".to_string(),
338                    )
339                })?;
340
341            // Convert back to slice
342            let result_array = scirs2_result.to_array1().map_err(|_| {
343                QuantRS2Error::ComputationError("Result conversion to array failed".to_string())
344            })?;
345            if let Some(slice) = result_array.as_slice() {
346                result.copy_from_slice(slice);
347            } else {
348                return Err(QuantRS2Error::ComputationError(
349                    "Result array is not contiguous".to_string(),
350                ));
351            }
352
353            Ok(())
354        } else {
355            // Fallback to manual implementation for smaller operations
356            for i in 0..result.len() {
357                result[i] = Complex64::new(0.0, 0.0);
358                for j in 0..vector.len() {
359                    result[i] += matrix[i * vector.len() + j] * vector[j];
360                }
361            }
362            Ok(())
363        }
364    }
365
366    /// Fallback dense matrix-vector multiplication for when `SciRS2` is not available
367    #[cfg(not(feature = "advanced_math"))]
368    fn apply_dense_matrix_vector(
369        &self,
370        matrix: &[Complex64],
371        vector: &[Complex64],
372        result: &mut [Complex64],
373    ) -> QuantRS2Result<()> {
374        // Manual implementation
375        for i in 0..result.len() {
376            result[i] = Complex64::new(0.0, 0.0);
377            for j in 0..vector.len() {
378                result[i] += matrix[i * vector.len() + j] * vector[j];
379            }
380        }
381        Ok(())
382    }
383
384    /// Apply a single-qubit gate to a state vector
385    fn apply_single_qubit_gate<const N: usize>(
386        &self,
387        state: &mut [Complex64],
388        gate_matrix: &[Complex64],
389        target: QubitId,
390    ) -> QuantRS2Result<()> {
391        let target_idx = target.id() as usize;
392        if target_idx >= N {
393            return Err(QuantRS2Error::InvalidQubitId(target.id()));
394        }
395
396        // Use SIMD optimization if enabled and beneficial
397        if self.use_simd && state.len() >= 8 {
398            return self.apply_single_qubit_gate_simd::<N>(state, gate_matrix, target_idx);
399        }
400
401        // Convert the gate matrix to flat representation for faster access
402        // Gate matrix: [m00, m01, m10, m11]
403        let m00 = gate_matrix[0];
404        let m01 = gate_matrix[1];
405        let m10 = gate_matrix[2];
406        let m11 = gate_matrix[3];
407
408        // Apply the gate to each amplitude
409        if self.parallel {
410            // Get buffer from pool for temporary storage
411            let mut state_copy = self
412                .buffer_pool
413                .lock()
414                .expect("buffer pool lock poisoned")
415                .get_buffer(state.len());
416            state_copy.copy_from_slice(state);
417
418            state.par_iter_mut().enumerate().for_each(|(idx, amp)| {
419                let bit_val = (idx >> target_idx) & 1;
420                let paired_idx = if bit_val == 0 {
421                    idx | (1 << target_idx)
422                } else {
423                    idx & !(1 << target_idx)
424                };
425
426                let idx0 = if bit_val == 0 { idx } else { paired_idx };
427                let idx1 = if bit_val == 0 { paired_idx } else { idx };
428
429                let val0 = state_copy[idx0];
430                let val1 = state_copy[idx1];
431
432                // Use direct matrix element access for better performance
433                *amp = if idx == idx0 {
434                    m00 * val0 + m01 * val1
435                } else {
436                    m10 * val0 + m11 * val1
437                };
438            });
439
440            // Return buffer to pool
441            self.buffer_pool
442                .lock()
443                .expect("buffer pool lock poisoned")
444                .return_buffer(state_copy);
445        } else {
446            // Sequential implementation using buffer pool
447            let dim = state.len();
448            let mut new_state = self
449                .buffer_pool
450                .lock()
451                .expect("buffer pool lock poisoned")
452                .get_buffer(dim);
453
454            for i in 0..dim {
455                let bit_val = (i >> target_idx) & 1;
456                let paired_idx = flip_bit(i, target_idx);
457
458                if bit_val == 0 {
459                    new_state[i] = m00 * state[i] + m01 * state[paired_idx];
460                    new_state[paired_idx] = m10 * state[i] + m11 * state[paired_idx];
461                }
462            }
463
464            state.copy_from_slice(&new_state);
465            // Return buffer to pool
466            self.buffer_pool
467                .lock()
468                .expect("buffer pool lock poisoned")
469                .return_buffer(new_state);
470        }
471
472        Ok(())
473    }
474
475    /// Apply a single-qubit gate using SIMD optimization
476    fn apply_single_qubit_gate_simd<const N: usize>(
477        &self,
478        state: &mut [Complex64],
479        gate_matrix: &[Complex64],
480        target_idx: usize,
481    ) -> QuantRS2Result<()> {
482        let dim = state.len();
483        let pairs_per_block = 1 << target_idx;
484        let total_pairs = dim / 2;
485
486        // Get buffers for SIMD processing
487        let mut pool = self.buffer_pool.lock().expect("buffer pool lock poisoned");
488        let mut in_amps0 = pool.get_buffer(total_pairs);
489        let mut in_amps1 = pool.get_buffer(total_pairs);
490        let mut out_amps0 = pool.get_buffer(total_pairs);
491        let mut out_amps1 = pool.get_buffer(total_pairs);
492
493        // Collect amplitudes for target bit = 0 and target bit = 1
494        let mut pair_idx = 0;
495        for block in 0..(dim / (pairs_per_block * 2)) {
496            let block_start = block * pairs_per_block * 2;
497
498            for offset in 0..pairs_per_block {
499                let idx0 = block_start + offset;
500                let idx1 = block_start + pairs_per_block + offset;
501
502                in_amps0[pair_idx] = state[idx0];
503                in_amps1[pair_idx] = state[idx1];
504                pair_idx += 1;
505            }
506        }
507
508        // Convert gate matrix to required format for SIMD
509        let gate_matrix_array: [Complex64; 4] = [
510            gate_matrix[0],
511            gate_matrix[1],
512            gate_matrix[2],
513            gate_matrix[3],
514        ];
515
516        // Apply SIMD gate operation
517        optimized_simd::apply_single_qubit_gate_optimized(
518            &gate_matrix_array,
519            &in_amps0,
520            &in_amps1,
521            &mut out_amps0,
522            &mut out_amps1,
523        );
524
525        // Write results back to state vector
526        pair_idx = 0;
527        for block in 0..(dim / (pairs_per_block * 2)) {
528            let block_start = block * pairs_per_block * 2;
529
530            for offset in 0..pairs_per_block {
531                let idx0 = block_start + offset;
532                let idx1 = block_start + pairs_per_block + offset;
533
534                state[idx0] = out_amps0[pair_idx];
535                state[idx1] = out_amps1[pair_idx];
536                pair_idx += 1;
537            }
538        }
539
540        // Return buffers to pool
541        pool.return_buffer(in_amps0);
542        pool.return_buffer(in_amps1);
543        pool.return_buffer(out_amps0);
544        pool.return_buffer(out_amps1);
545
546        Ok(())
547    }
548
549    /// Apply a two-qubit gate to a state vector
550    fn apply_two_qubit_gate<const N: usize>(
551        &self,
552        state: &mut [Complex64],
553        gate_matrix: &[Complex64],
554        control: QubitId,
555        target: QubitId,
556    ) -> QuantRS2Result<()> {
557        let control_idx = control.id() as usize;
558        let target_idx = target.id() as usize;
559
560        if control_idx >= N || target_idx >= N {
561            return Err(QuantRS2Error::InvalidQubitId(if control_idx >= N {
562                control.id()
563            } else {
564                target.id()
565            }));
566        }
567
568        if control_idx == target_idx {
569            return Err(QuantRS2Error::CircuitValidationFailed(
570                "Control and target qubits must be different".into(),
571            ));
572        }
573
574        // Pre-extract matrix elements for faster access (16 elements total)
575        let m = gate_matrix; // Direct slice access is faster than ndarray indexing
576
577        // Apply the gate to each amplitude
578        if self.parallel {
579            // Get buffer from pool for temporary storage
580            let mut state_copy = self
581                .buffer_pool
582                .lock()
583                .expect("buffer pool lock poisoned")
584                .get_buffer(state.len());
585            state_copy.copy_from_slice(state);
586
587            state.par_iter_mut().enumerate().for_each(|(idx, amp)| {
588                let idx00 = idx & !(1 << control_idx) & !(1 << target_idx);
589                let idx01 = idx00 | (1 << target_idx);
590                let idx10 = idx00 | (1 << control_idx);
591                let idx11 = idx00 | (1 << control_idx) | (1 << target_idx);
592
593                let val00 = state_copy[idx00];
594                let val01 = state_copy[idx01];
595                let val10 = state_copy[idx10];
596                let val11 = state_copy[idx11];
597
598                // Use direct matrix access for better performance
599                *amp = match idx {
600                    i if i == idx00 => m[0] * val00 + m[1] * val01 + m[2] * val10 + m[3] * val11,
601                    i if i == idx01 => m[4] * val00 + m[5] * val01 + m[6] * val10 + m[7] * val11,
602                    i if i == idx10 => m[8] * val00 + m[9] * val01 + m[10] * val10 + m[11] * val11,
603                    i if i == idx11 => {
604                        m[12] * val00 + m[13] * val01 + m[14] * val10 + m[15] * val11
605                    }
606                    _ => unreachable!(),
607                };
608            });
609
610            // Return buffer to pool
611            self.buffer_pool
612                .lock()
613                .expect("buffer pool lock poisoned")
614                .return_buffer(state_copy);
615        } else {
616            // Sequential implementation using buffer pool
617            let dim = state.len();
618            let mut new_state = self
619                .buffer_pool
620                .lock()
621                .expect("buffer pool lock poisoned")
622                .get_buffer(dim);
623
624            #[allow(clippy::needless_range_loop)]
625            for i in 0..dim {
626                let control_bit = (i >> control_idx) & 1;
627                let target_bit = (i >> target_idx) & 1;
628
629                // Calculate the four basis states in the 2-qubit subspace
630                let i00 = i & !(1 << control_idx) & !(1 << target_idx);
631                let i01 = i00 | (1 << target_idx);
632                let i10 = i00 | (1 << control_idx);
633                let i11 = i10 | (1 << target_idx);
634
635                let basis_idx = (control_bit << 1) | target_bit;
636
637                // Calculate the new amplitude for this state using direct access
638                let row_offset = basis_idx * 4;
639                new_state[i] = m[row_offset] * state[i00]
640                    + m[row_offset + 1] * state[i01]
641                    + m[row_offset + 2] * state[i10]
642                    + m[row_offset + 3] * state[i11];
643            }
644
645            state.copy_from_slice(&new_state);
646            // Return buffer to pool
647            self.buffer_pool
648                .lock()
649                .expect("buffer pool lock poisoned")
650                .return_buffer(new_state);
651        }
652
653        Ok(())
654    }
655
656    /// Apply CNOT gate efficiently (special case)
657    fn apply_cnot<const N: usize>(
658        &self,
659        state: &mut [Complex64],
660        control: QubitId,
661        target: QubitId,
662    ) -> QuantRS2Result<()> {
663        let control_idx = control.id() as usize;
664        let target_idx = target.id() as usize;
665
666        if control_idx >= N || target_idx >= N {
667            return Err(QuantRS2Error::InvalidQubitId(if control_idx >= N {
668                control.id()
669            } else {
670                target.id()
671            }));
672        }
673
674        if control_idx == target_idx {
675            return Err(QuantRS2Error::CircuitValidationFailed(
676                "Control and target qubits must be different".into(),
677            ));
678        }
679
680        // Apply the CNOT gate - only swap amplitudes where control is 1
681        if self.parallel {
682            let mut state_copy = self
683                .buffer_pool
684                .lock()
685                .expect("buffer pool lock poisoned")
686                .get_buffer(state.len());
687            state_copy.copy_from_slice(state);
688
689            state.par_iter_mut().enumerate().for_each(|(i, amp)| {
690                if (i >> control_idx) & 1 == 1 {
691                    let flipped = flip_bit(i, target_idx);
692                    *amp = state_copy[flipped];
693                }
694            });
695
696            self.buffer_pool
697                .lock()
698                .expect("buffer pool lock poisoned")
699                .return_buffer(state_copy);
700        } else {
701            let dim = state.len();
702            let mut new_state = self
703                .buffer_pool
704                .lock()
705                .expect("buffer pool lock poisoned")
706                .get_buffer(dim);
707
708            for i in 0..dim {
709                if (i >> control_idx) & 1 == 1 {
710                    let flipped = flip_bit(i, target_idx);
711                    new_state[flipped] = state[i];
712                    new_state[i] = state[flipped];
713                } else {
714                    new_state[i] = state[i];
715                }
716            }
717
718            state.copy_from_slice(&new_state);
719            self.buffer_pool
720                .lock()
721                .expect("buffer pool lock poisoned")
722                .return_buffer(new_state);
723        }
724
725        Ok(())
726    }
727
728    /// Apply SWAP gate efficiently (special case)
729    fn apply_swap<const N: usize>(
730        &self,
731        state: &mut [Complex64],
732        qubit1: QubitId,
733        qubit2: QubitId,
734    ) -> QuantRS2Result<()> {
735        let q1_idx = qubit1.id() as usize;
736        let q2_idx = qubit2.id() as usize;
737
738        if q1_idx >= N || q2_idx >= N {
739            return Err(QuantRS2Error::InvalidQubitId(if q1_idx >= N {
740                qubit1.id()
741            } else {
742                qubit2.id()
743            }));
744        }
745
746        if q1_idx == q2_idx {
747            return Err(QuantRS2Error::CircuitValidationFailed(
748                "Qubits must be different for SWAP gate".into(),
749            ));
750        }
751
752        // Apply the SWAP gate - swap amplitudes where qubits have different values
753        if self.parallel {
754            let mut state_copy = self
755                .buffer_pool
756                .lock()
757                .expect("buffer pool lock poisoned")
758                .get_buffer(state.len());
759            state_copy.copy_from_slice(state);
760
761            state.par_iter_mut().enumerate().for_each(|(i, amp)| {
762                let bit1 = (i >> q1_idx) & 1;
763                let bit2 = (i >> q2_idx) & 1;
764
765                if bit1 != bit2 {
766                    let swapped = flip_bit(flip_bit(i, q1_idx), q2_idx);
767                    *amp = state_copy[swapped];
768                }
769            });
770
771            self.buffer_pool
772                .lock()
773                .expect("buffer pool lock poisoned")
774                .return_buffer(state_copy);
775        } else {
776            let dim = state.len();
777            let mut new_state = self
778                .buffer_pool
779                .lock()
780                .expect("buffer pool lock poisoned")
781                .get_buffer(dim);
782
783            for i in 0..dim {
784                let bit1 = (i >> q1_idx) & 1;
785                let bit2 = (i >> q2_idx) & 1;
786
787                if bit1 == bit2 {
788                    new_state[i] = state[i];
789                } else {
790                    let swapped = flip_bit(flip_bit(i, q1_idx), q2_idx);
791                    new_state[swapped] = state[i];
792                    new_state[i] = state[swapped];
793                }
794            }
795
796            state.copy_from_slice(&new_state);
797            self.buffer_pool
798                .lock()
799                .expect("buffer pool lock poisoned")
800                .return_buffer(new_state);
801        }
802
803        Ok(())
804    }
805}
806
807impl Default for StateVectorSimulator {
808    fn default() -> Self {
809        Self::new()
810    }
811}
812
813impl<const N: usize> Simulator<N> for StateVectorSimulator {
814    fn run(&self, circuit: &Circuit<N>) -> QuantRS2Result<Register<N>> {
815        // Initialize state vector to |0...0⟩
816        let dim = 1 << N;
817        let mut state = vec![Complex64::new(0.0, 0.0); dim];
818        state[0] = Complex64::new(1.0, 0.0);
819
820        // Apply each gate in the circuit
821        for gate in circuit.gates() {
822            match gate.name() {
823                // Single-qubit gates
824                "H" => {
825                    if let Some(g) = gate.as_any().downcast_ref::<single::Hadamard>() {
826                        let matrix = g.matrix()?;
827                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
828                    }
829                }
830                "X" => {
831                    if let Some(g) = gate.as_any().downcast_ref::<single::PauliX>() {
832                        let matrix = g.matrix()?;
833                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
834                    }
835                }
836                "Y" => {
837                    if let Some(g) = gate.as_any().downcast_ref::<single::PauliY>() {
838                        let matrix = g.matrix()?;
839                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
840                    }
841                }
842                "Z" => {
843                    if let Some(g) = gate.as_any().downcast_ref::<single::PauliZ>() {
844                        let matrix = g.matrix()?;
845                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
846                    }
847                }
848                "RX" => {
849                    if let Some(g) = gate.as_any().downcast_ref::<single::RotationX>() {
850                        let matrix = g.matrix()?;
851                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
852                    }
853                }
854                "RY" => {
855                    if let Some(g) = gate.as_any().downcast_ref::<single::RotationY>() {
856                        let matrix = g.matrix()?;
857                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
858                    }
859                }
860                "RZ" => {
861                    if let Some(g) = gate.as_any().downcast_ref::<single::RotationZ>() {
862                        let matrix = g.matrix()?;
863                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
864                    }
865                }
866                "S" => {
867                    if let Some(g) = gate.as_any().downcast_ref::<single::Phase>() {
868                        let matrix = g.matrix()?;
869                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
870                    }
871                }
872                "T" => {
873                    if let Some(g) = gate.as_any().downcast_ref::<single::T>() {
874                        let matrix = g.matrix()?;
875                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
876                    }
877                }
878                "S†" => {
879                    if let Some(g) = gate.as_any().downcast_ref::<single::PhaseDagger>() {
880                        let matrix = g.matrix()?;
881                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
882                    }
883                }
884                "T†" => {
885                    if let Some(g) = gate.as_any().downcast_ref::<single::TDagger>() {
886                        let matrix = g.matrix()?;
887                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
888                    }
889                }
890                "√X" => {
891                    if let Some(g) = gate.as_any().downcast_ref::<single::SqrtX>() {
892                        let matrix = g.matrix()?;
893                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
894                    }
895                }
896                "√X†" => {
897                    if let Some(g) = gate.as_any().downcast_ref::<single::SqrtXDagger>() {
898                        let matrix = g.matrix()?;
899                        self.apply_single_qubit_gate::<N>(&mut state, &matrix, g.target)?;
900                    }
901                }
902
903                // Two-qubit gates
904                "CNOT" => {
905                    if let Some(g) = gate.as_any().downcast_ref::<multi::CNOT>() {
906                        // Use optimized implementation for CNOT
907                        self.apply_cnot::<N>(&mut state, g.control, g.target)?;
908                    }
909                }
910                "CZ" => {
911                    if let Some(g) = gate.as_any().downcast_ref::<multi::CZ>() {
912                        let matrix = g.matrix()?;
913                        self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
914                    }
915                }
916                "SWAP" => {
917                    if let Some(g) = gate.as_any().downcast_ref::<multi::SWAP>() {
918                        // Use optimized implementation for SWAP
919                        self.apply_swap::<N>(&mut state, g.qubit1, g.qubit2)?;
920                    }
921                }
922                "CY" => {
923                    if let Some(g) = gate.as_any().downcast_ref::<multi::CY>() {
924                        let matrix = g.matrix()?;
925                        self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
926                    }
927                }
928                "CH" => {
929                    if let Some(g) = gate.as_any().downcast_ref::<multi::CH>() {
930                        let matrix = g.matrix()?;
931                        self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
932                    }
933                }
934                "CS" => {
935                    if let Some(g) = gate.as_any().downcast_ref::<multi::CS>() {
936                        let matrix = g.matrix()?;
937                        self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
938                    }
939                }
940                "CRX" => {
941                    if let Some(g) = gate.as_any().downcast_ref::<multi::CRX>() {
942                        let matrix = g.matrix()?;
943                        self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
944                    }
945                }
946                "CRY" => {
947                    if let Some(g) = gate.as_any().downcast_ref::<multi::CRY>() {
948                        let matrix = g.matrix()?;
949                        self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
950                    }
951                }
952                "CRZ" => {
953                    if let Some(g) = gate.as_any().downcast_ref::<multi::CRZ>() {
954                        let matrix = g.matrix()?;
955                        self.apply_two_qubit_gate::<N>(&mut state, &matrix, g.control, g.target)?;
956                    }
957                }
958
959                // Three-qubit gates
960                "Toffoli" => {
961                    if let Some(toffoli_gate) = gate.as_any().downcast_ref::<multi::Toffoli>() {
962                        let control1 = toffoli_gate.control1;
963                        let control2 = toffoli_gate.control2;
964                        let target = toffoli_gate.target;
965                        self.apply_toffoli_to_state::<N>(&mut state, control1, control2, target)?;
966                    }
967                }
968                "Fredkin" => {
969                    if let Some(fredkin_gate) = gate.as_any().downcast_ref::<multi::Fredkin>() {
970                        let control = fredkin_gate.control;
971                        let target1 = fredkin_gate.target1;
972                        let target2 = fredkin_gate.target2;
973                        self.apply_fredkin_to_state::<N>(&mut state, control, target1, target2)?;
974                    }
975                }
976
977                _ => {
978                    return Err(QuantRS2Error::UnsupportedOperation(format!(
979                        "Gate {} not supported",
980                        gate.name()
981                    )));
982                }
983            }
984
985            // Apply per-gate noise if configured
986            if let Some(ref noise_model) = self.noise_model {
987                if noise_model.per_gate {
988                    noise_model.apply_to_statevector(&mut state)?;
989                }
990            }
991
992            // Apply per-gate advanced noise if configured
993            if let Some(ref advanced_noise_model) = self.advanced_noise_model {
994                if advanced_noise_model.per_gate {
995                    advanced_noise_model.apply_to_statevector(&mut state)?;
996                }
997            }
998        }
999
1000        // Apply final noise if not per-gate
1001        if let Some(ref noise_model) = self.noise_model {
1002            if !noise_model.per_gate {
1003                noise_model.apply_to_statevector(&mut state)?;
1004            }
1005        }
1006
1007        // Apply final advanced noise if not per-gate
1008        if let Some(ref advanced_noise_model) = self.advanced_noise_model {
1009            if !advanced_noise_model.per_gate {
1010                advanced_noise_model.apply_to_statevector(&mut state)?;
1011            }
1012        }
1013
1014        // Create register from final state
1015        Register::<N>::with_amplitudes(state)
1016    }
1017}
1018
1019impl StateVectorSimulator {
1020    /// Initialize state with specified number of qubits in |0...0⟩
1021    pub const fn initialize_state(&mut self, num_qubits: usize) -> QuantRS2Result<()> {
1022        // This is a placeholder - actual initialization would need the circuit framework
1023        Ok(())
1024    }
1025
1026    /// Get the current quantum state
1027    pub fn get_state(&self) -> Vec<Complex64> {
1028        // Placeholder - would return the actual state vector
1029        vec![Complex64::new(1.0, 0.0)]
1030    }
1031
1032    /// Get mutable reference to the current quantum state
1033    pub fn get_state_mut(&mut self) -> Vec<Complex64> {
1034        // Placeholder - would return mutable reference to actual state vector
1035        vec![Complex64::new(1.0, 0.0)]
1036    }
1037
1038    /// Set the quantum state
1039    pub fn set_state(&mut self, _state: Vec<Complex64>) -> QuantRS2Result<()> {
1040        // Placeholder - would set the actual state vector
1041        Ok(())
1042    }
1043
1044    /// Apply an interface circuit to the quantum state
1045    pub const fn apply_interface_circuit(
1046        &mut self,
1047        _circuit: &crate::circuit_interfaces::InterfaceCircuit,
1048    ) -> QuantRS2Result<()> {
1049        // Placeholder - would apply the circuit gates using the circuit framework
1050        Ok(())
1051    }
1052
1053    /// Apply Hadamard gate to qubit
1054    pub const fn apply_h(&mut self, _qubit: usize) -> QuantRS2Result<()> {
1055        // Placeholder - would apply H gate using circuit framework
1056        Ok(())
1057    }
1058
1059    /// Apply Pauli-X gate to qubit
1060    pub const fn apply_x(&mut self, _qubit: usize) -> QuantRS2Result<()> {
1061        // Placeholder - would apply X gate using circuit framework
1062        Ok(())
1063    }
1064
1065    /// Apply Pauli-Z gate to qubit
1066    pub const fn apply_z_public(&mut self, _qubit: usize) -> QuantRS2Result<()> {
1067        // Placeholder - would apply Z gate using circuit framework
1068        Ok(())
1069    }
1070
1071    /// Apply CNOT gate (public interface with usize indices)
1072    pub const fn apply_cnot_public(
1073        &mut self,
1074        _control: usize,
1075        _target: usize,
1076    ) -> QuantRS2Result<()> {
1077        // Placeholder - would apply CNOT gate using circuit framework
1078        Ok(())
1079    }
1080
1081    /// Apply Toffoli (CCNOT) gate to state vector
1082    fn apply_toffoli_to_state<const N: usize>(
1083        &self,
1084        state: &mut [Complex64],
1085        control1: QubitId,
1086        control2: QubitId,
1087        target: QubitId,
1088    ) -> QuantRS2Result<()> {
1089        let control1_idx = control1.id() as usize;
1090        let control2_idx = control2.id() as usize;
1091        let target_idx = target.id() as usize;
1092
1093        if control1_idx >= N || control2_idx >= N || target_idx >= N {
1094            return Err(QuantRS2Error::InvalidQubitId(if control1_idx >= N {
1095                control1.id()
1096            } else if control2_idx >= N {
1097                control2.id()
1098            } else {
1099                target.id()
1100            }));
1101        }
1102
1103        // Apply Toffoli gate by swapping amplitudes when both controls are |1⟩
1104        if self.parallel {
1105            let mut state_copy = self
1106                .buffer_pool
1107                .lock()
1108                .expect("buffer pool lock poisoned")
1109                .get_buffer(state.len());
1110            state_copy.copy_from_slice(state);
1111
1112            state.par_iter_mut().enumerate().for_each(|(i, amp)| {
1113                let control1_bit = (i >> control1_idx) & 1;
1114                let control2_bit = (i >> control2_idx) & 1;
1115
1116                if control1_bit == 1 && control2_bit == 1 {
1117                    let flipped = flip_bit(i, target_idx);
1118                    *amp = state_copy[flipped];
1119                }
1120            });
1121
1122            self.buffer_pool
1123                .lock()
1124                .expect("buffer pool lock poisoned")
1125                .return_buffer(state_copy);
1126        } else {
1127            let mut new_state = self
1128                .buffer_pool
1129                .lock()
1130                .expect("buffer pool lock poisoned")
1131                .get_buffer(state.len());
1132            new_state.copy_from_slice(state);
1133
1134            for i in 0..state.len() {
1135                let control1_bit = (i >> control1_idx) & 1;
1136                let control2_bit = (i >> control2_idx) & 1;
1137
1138                if control1_bit == 1 && control2_bit == 1 {
1139                    let flipped = flip_bit(i, target_idx);
1140                    new_state[flipped] = state[i];
1141                    new_state[i] = state[flipped];
1142                }
1143            }
1144
1145            state.copy_from_slice(&new_state);
1146            self.buffer_pool
1147                .lock()
1148                .expect("buffer pool lock poisoned")
1149                .return_buffer(new_state);
1150        }
1151
1152        Ok(())
1153    }
1154
1155    /// Apply Fredkin (CSWAP) gate to state vector
1156    fn apply_fredkin_to_state<const N: usize>(
1157        &self,
1158        state: &mut [Complex64],
1159        control: QubitId,
1160        target1: QubitId,
1161        target2: QubitId,
1162    ) -> QuantRS2Result<()> {
1163        let control_idx = control.id() as usize;
1164        let target1_idx = target1.id() as usize;
1165        let target2_idx = target2.id() as usize;
1166
1167        if control_idx >= N || target1_idx >= N || target2_idx >= N {
1168            return Err(QuantRS2Error::InvalidQubitId(if control_idx >= N {
1169                control.id()
1170            } else if target1_idx >= N {
1171                target1.id()
1172            } else {
1173                target2.id()
1174            }));
1175        }
1176
1177        // Apply Fredkin gate by swapping target qubits when control is |1⟩
1178        if self.parallel {
1179            let mut state_copy = self
1180                .buffer_pool
1181                .lock()
1182                .expect("buffer pool lock poisoned")
1183                .get_buffer(state.len());
1184            state_copy.copy_from_slice(state);
1185
1186            state.par_iter_mut().enumerate().for_each(|(i, amp)| {
1187                let control_bit = (i >> control_idx) & 1;
1188                let target1_bit = (i >> target1_idx) & 1;
1189                let target2_bit = (i >> target2_idx) & 1;
1190
1191                if control_bit == 1 && target1_bit != target2_bit {
1192                    let swapped = flip_bit(flip_bit(i, target1_idx), target2_idx);
1193                    *amp = state_copy[swapped];
1194                }
1195            });
1196
1197            self.buffer_pool
1198                .lock()
1199                .expect("buffer pool lock poisoned")
1200                .return_buffer(state_copy);
1201        } else {
1202            let mut new_state = self
1203                .buffer_pool
1204                .lock()
1205                .expect("buffer pool lock poisoned")
1206                .get_buffer(state.len());
1207            new_state.copy_from_slice(state);
1208
1209            for i in 0..state.len() {
1210                let control_bit = (i >> control_idx) & 1;
1211                let target1_bit = (i >> target1_idx) & 1;
1212                let target2_bit = (i >> target2_idx) & 1;
1213
1214                if control_bit == 1 && target1_bit != target2_bit {
1215                    let swapped = flip_bit(flip_bit(i, target1_idx), target2_idx);
1216                    new_state[swapped] = state[i];
1217                    new_state[i] = state[swapped];
1218                }
1219            }
1220
1221            state.copy_from_slice(&new_state);
1222            self.buffer_pool
1223                .lock()
1224                .expect("buffer pool lock poisoned")
1225                .return_buffer(new_state);
1226        }
1227
1228        Ok(())
1229    }
1230
1231    /// Apply Toffoli (CCNOT) gate (public interface)
1232    pub const fn apply_toffoli(
1233        &mut self,
1234        control1: QubitId,
1235        control2: QubitId,
1236        target: QubitId,
1237    ) -> QuantRS2Result<()> {
1238        // This is a placeholder for external API - real implementation would need circuit framework
1239        Ok(())
1240    }
1241
1242    /// Apply Fredkin (CSWAP) gate (public interface)
1243    pub const fn apply_fredkin(
1244        &mut self,
1245        control: QubitId,
1246        target1: QubitId,
1247        target2: QubitId,
1248    ) -> QuantRS2Result<()> {
1249        // This is a placeholder for external API - real implementation would need circuit framework
1250        Ok(())
1251    }
1252}