quantrs2_sim/
dynamic.rs

1use crate::simulator::Simulator; // Local simulator trait
2#[cfg(feature = "python")]
3use pyo3::exceptions::PyValueError;
4#[cfg(feature = "python")]
5use pyo3::PyResult;
6use quantrs2_circuit::builder::Circuit;
7use quantrs2_circuit::builder::Simulator as CircuitSimulator; // Circuit simulator trait
8use quantrs2_core::{
9    error::{QuantRS2Error, QuantRS2Result},
10    gate::GateOp,
11};
12use scirs2_core::Complex64;
13
14// Unused imports
15#[allow(unused_imports)]
16use crate::simulator::SimulatorResult;
17use crate::statevector::StateVectorSimulator;
18#[allow(unused_imports)]
19use quantrs2_core::qubit::QubitId;
20#[allow(unused_imports)]
21use std::collections::HashMap;
22
23#[cfg(all(feature = "gpu", not(target_os = "macos")))]
24use crate::gpu::GpuStateVectorSimulator;
25
26/// A dynamic circuit that encapsulates circuits of different qubit counts
27pub enum DynamicCircuit {
28    /// 2-qubit circuit
29    Q2(Circuit<2>),
30    /// 3-qubit circuit
31    Q3(Circuit<3>),
32    /// 4-qubit circuit
33    Q4(Circuit<4>),
34    /// 5-qubit circuit
35    Q5(Circuit<5>),
36    /// 6-qubit circuit
37    Q6(Circuit<6>),
38    /// 7-qubit circuit
39    Q7(Circuit<7>),
40    /// 8-qubit circuit
41    Q8(Circuit<8>),
42    /// 9-qubit circuit
43    Q9(Circuit<9>),
44    /// 10-qubit circuit
45    Q10(Circuit<10>),
46    /// 12-qubit circuit
47    Q12(Circuit<12>),
48    /// 16-qubit circuit
49    Q16(Circuit<16>),
50    /// 20-qubit circuit
51    Q20(Circuit<20>),
52    /// 24-qubit circuit
53    Q24(Circuit<24>),
54    /// 32-qubit circuit
55    Q32(Circuit<32>),
56}
57
58impl DynamicCircuit {
59    /// Create a new dynamic circuit with the specified number of qubits
60    pub fn new(n_qubits: usize) -> QuantRS2Result<Self> {
61        match n_qubits {
62            2 => Ok(Self::Q2(Circuit::<2>::new())),
63            3 => Ok(Self::Q3(Circuit::<3>::new())),
64            4 => Ok(Self::Q4(Circuit::<4>::new())),
65            5 => Ok(Self::Q5(Circuit::<5>::new())),
66            6 => Ok(Self::Q6(Circuit::<6>::new())),
67            7 => Ok(Self::Q7(Circuit::<7>::new())),
68            8 => Ok(Self::Q8(Circuit::<8>::new())),
69            9 => Ok(Self::Q9(Circuit::<9>::new())),
70            10 => Ok(Self::Q10(Circuit::<10>::new())),
71            12 => Ok(Self::Q12(Circuit::<12>::new())),
72            16 => Ok(Self::Q16(Circuit::<16>::new())),
73            20 => Ok(Self::Q20(Circuit::<20>::new())),
74            24 => Ok(Self::Q24(Circuit::<24>::new())),
75            32 => Ok(Self::Q32(Circuit::<32>::new())),
76            _ => Err(QuantRS2Error::UnsupportedQubits(
77                n_qubits,
78                "Supported qubit counts are 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16, 20, 24, and 32."
79                    .to_string(),
80            )),
81        }
82    }
83
84    /// Get the list of gate names in the circuit
85    pub fn gates(&self) -> Vec<String> {
86        self.get_gate_names()
87    }
88
89    // This method is duplicated later in the file, removing it here
90
91    // This method is duplicated later in the file, removing it here
92
93    // This method is duplicated later in the file, removing it here
94
95    // This method is duplicated later in the file, removing it here
96
97    // This method is duplicated later in the file, removing it here
98
99    /// Get the number of qubits in the circuit
100    pub const fn num_qubits(&self) -> usize {
101        match self {
102            Self::Q2(_) => 2,
103            Self::Q3(_) => 3,
104            Self::Q4(_) => 4,
105            Self::Q5(_) => 5,
106            Self::Q6(_) => 6,
107            Self::Q7(_) => 7,
108            Self::Q8(_) => 8,
109            Self::Q9(_) => 9,
110            Self::Q10(_) => 10,
111            Self::Q12(_) => 12,
112            Self::Q16(_) => 16,
113            Self::Q20(_) => 20,
114            Self::Q24(_) => 24,
115            Self::Q32(_) => 32,
116        }
117    }
118
119    /// Get the gate names in the circuit
120    pub fn get_gate_names(&self) -> Vec<String> {
121        match self {
122            Self::Q2(c) => c
123                .gates()
124                .iter()
125                .map(|gate| gate.name().to_string())
126                .collect(),
127            Self::Q3(c) => c
128                .gates()
129                .iter()
130                .map(|gate| gate.name().to_string())
131                .collect(),
132            Self::Q4(c) => c
133                .gates()
134                .iter()
135                .map(|gate| gate.name().to_string())
136                .collect(),
137            Self::Q5(c) => c
138                .gates()
139                .iter()
140                .map(|gate| gate.name().to_string())
141                .collect(),
142            Self::Q6(c) => c
143                .gates()
144                .iter()
145                .map(|gate| gate.name().to_string())
146                .collect(),
147            Self::Q7(c) => c
148                .gates()
149                .iter()
150                .map(|gate| gate.name().to_string())
151                .collect(),
152            Self::Q8(c) => c
153                .gates()
154                .iter()
155                .map(|gate| gate.name().to_string())
156                .collect(),
157            Self::Q9(c) => c
158                .gates()
159                .iter()
160                .map(|gate| gate.name().to_string())
161                .collect(),
162            Self::Q10(c) => c
163                .gates()
164                .iter()
165                .map(|gate| gate.name().to_string())
166                .collect(),
167            Self::Q12(c) => c
168                .gates()
169                .iter()
170                .map(|gate| gate.name().to_string())
171                .collect(),
172            Self::Q16(c) => c
173                .gates()
174                .iter()
175                .map(|gate| gate.name().to_string())
176                .collect(),
177            Self::Q20(c) => c
178                .gates()
179                .iter()
180                .map(|gate| gate.name().to_string())
181                .collect(),
182            Self::Q24(c) => c
183                .gates()
184                .iter()
185                .map(|gate| gate.name().to_string())
186                .collect(),
187            Self::Q32(c) => c
188                .gates()
189                .iter()
190                .map(|gate| gate.name().to_string())
191                .collect(),
192        }
193    }
194
195    /// Get the qubit for single-qubit gate
196    #[cfg(feature = "python")]
197    pub fn get_single_qubit_for_gate(&self, gate_type: &str, index: usize) -> PyResult<u32> {
198        // Placeholder for visualization - in a real implementation, we would track this information
199        let gate_name = gate_type.to_string();
200        let gates = self.get_gate_names();
201
202        // Find the Nth occurrence of this gate type
203        let mut count = 0;
204        for (i, name) in gates.iter().enumerate() {
205            if name == &gate_name {
206                if count == index {
207                    // Return a placeholder qubit ID - in a real implementation this would be accurate
208                    match self {
209                        Self::Q2(c) => {
210                            if let Some(gate) = c.gates().get(i) {
211                                if gate.qubits().len() == 1 {
212                                    return Ok(gate.qubits()[0].id());
213                                }
214                            }
215                        }
216                        // Repeat for all other qubit counts
217                        _ => return Ok(0),
218                    }
219                }
220                count += 1;
221            }
222        }
223
224        Err(PyValueError::new_err(format!(
225            "Gate {gate_type} at index {index} not found"
226        )))
227    }
228
229    /// Get the parameters for a rotation gate
230    #[cfg(feature = "python")]
231    pub fn get_rotation_params_for_gate(
232        &self,
233        gate_type: &str,
234        index: usize,
235    ) -> PyResult<(u32, f64)> {
236        // Placeholder for visualization - in a real implementation, we would track this information
237        let gate_name = gate_type.to_string();
238        let gates = self.get_gate_names();
239
240        // Find the Nth occurrence of this gate type
241        let mut count = 0;
242        for name in &gates {
243            if name == &gate_name {
244                if count == index {
245                    // Return placeholder values - in a real implementation these would be accurate
246                    return Ok((0, 0.0));
247                }
248                count += 1;
249            }
250        }
251
252        Err(PyValueError::new_err(format!(
253            "Gate {gate_type} at index {index} not found"
254        )))
255    }
256
257    /// Get the parameters for a two-qubit gate
258    #[cfg(feature = "python")]
259    pub fn get_two_qubit_params_for_gate(
260        &self,
261        gate_type: &str,
262        index: usize,
263    ) -> PyResult<(u32, u32)> {
264        // Placeholder for visualization - in a real implementation, we would track this information
265        let gate_name = gate_type.to_string();
266        let gates = self.get_gate_names();
267
268        // Find the Nth occurrence of this gate type
269        let mut count = 0;
270        for name in &gates {
271            if name == &gate_name {
272                if count == index {
273                    // Return placeholder values - in a real implementation these would be accurate
274                    return Ok((0, 1));
275                }
276                count += 1;
277            }
278        }
279
280        Err(PyValueError::new_err(format!(
281            "Gate {gate_type} at index {index} not found"
282        )))
283    }
284
285    /// Get the parameters for a controlled rotation gate
286    #[cfg(feature = "python")]
287    pub fn get_controlled_rotation_params_for_gate(
288        &self,
289        gate_type: &str,
290        index: usize,
291    ) -> PyResult<(u32, u32, f64)> {
292        // Placeholder for visualization - in a real implementation, we would track this information
293        let gate_name = gate_type.to_string();
294        let gates = self.get_gate_names();
295
296        // Find the Nth occurrence of this gate type
297        let mut count = 0;
298        for name in &gates {
299            if name == &gate_name {
300                if count == index {
301                    // Return placeholder values - in a real implementation these would be accurate
302                    return Ok((0, 1, 0.0));
303                }
304                count += 1;
305            }
306        }
307
308        Err(PyValueError::new_err(format!(
309            "Gate {gate_type} at index {index} not found"
310        )))
311    }
312
313    /// Get the parameters for a three-qubit gate
314    #[cfg(feature = "python")]
315    pub fn get_three_qubit_params_for_gate(
316        &self,
317        gate_type: &str,
318        index: usize,
319    ) -> PyResult<(u32, u32, u32)> {
320        // Placeholder for visualization - in a real implementation, we would track this information
321        let gate_name = gate_type.to_string();
322        let gates = self.get_gate_names();
323
324        // Find the Nth occurrence of this gate type
325        let mut count = 0;
326        for name in &gates {
327            if name == &gate_name {
328                if count == index {
329                    // Return placeholder values - in a real implementation these would be accurate
330                    return Ok((0, 1, 2));
331                }
332                count += 1;
333            }
334        }
335
336        Err(PyValueError::new_err(format!(
337            "Gate {gate_type} at index {index} not found"
338        )))
339    }
340
341    /// Apply a gate to the circuit
342    pub fn apply_gate<G: GateOp + Clone + Send + Sync + 'static>(
343        &mut self,
344        gate: G,
345    ) -> QuantRS2Result<()> {
346        match self {
347            Self::Q2(c) => c.add_gate(gate).map(|_| ()),
348            Self::Q3(c) => c.add_gate(gate).map(|_| ()),
349            Self::Q4(c) => c.add_gate(gate).map(|_| ()),
350            Self::Q5(c) => c.add_gate(gate).map(|_| ()),
351            Self::Q6(c) => c.add_gate(gate).map(|_| ()),
352            Self::Q7(c) => c.add_gate(gate).map(|_| ()),
353            Self::Q8(c) => c.add_gate(gate).map(|_| ()),
354            Self::Q9(c) => c.add_gate(gate).map(|_| ()),
355            Self::Q10(c) => c.add_gate(gate).map(|_| ()),
356            Self::Q12(c) => c.add_gate(gate).map(|_| ()),
357            Self::Q16(c) => c.add_gate(gate).map(|_| ()),
358            Self::Q20(c) => c.add_gate(gate).map(|_| ()),
359            Self::Q24(c) => c.add_gate(gate).map(|_| ()),
360            Self::Q32(c) => c.add_gate(gate).map(|_| ()),
361        }
362    }
363
364    /// Run the circuit on a CPU simulator
365    pub fn run(&self, simulator: &StateVectorSimulator) -> QuantRS2Result<DynamicResult> {
366        match self {
367            Self::Q2(c) => {
368                let result = simulator.run(c)?;
369                Ok(DynamicResult {
370                    amplitudes: result.amplitudes().to_vec(),
371                    num_qubits: 2,
372                })
373            }
374            Self::Q3(c) => {
375                let result = simulator.run(c)?;
376                Ok(DynamicResult {
377                    amplitudes: result.amplitudes().to_vec(),
378                    num_qubits: 3,
379                })
380            }
381            Self::Q4(c) => {
382                let result = simulator.run(c)?;
383                Ok(DynamicResult {
384                    amplitudes: result.amplitudes().to_vec(),
385                    num_qubits: 4,
386                })
387            }
388            Self::Q5(c) => {
389                let result = simulator.run(c)?;
390                Ok(DynamicResult {
391                    amplitudes: result.amplitudes().to_vec(),
392                    num_qubits: 5,
393                })
394            }
395            Self::Q6(c) => {
396                let result = simulator.run(c)?;
397                Ok(DynamicResult {
398                    amplitudes: result.amplitudes().to_vec(),
399                    num_qubits: 6,
400                })
401            }
402            Self::Q7(c) => {
403                let result = simulator.run(c)?;
404                Ok(DynamicResult {
405                    amplitudes: result.amplitudes().to_vec(),
406                    num_qubits: 7,
407                })
408            }
409            Self::Q8(c) => {
410                let result = simulator.run(c)?;
411                Ok(DynamicResult {
412                    amplitudes: result.amplitudes().to_vec(),
413                    num_qubits: 8,
414                })
415            }
416            Self::Q9(c) => {
417                let result = simulator.run(c)?;
418                Ok(DynamicResult {
419                    amplitudes: result.amplitudes().to_vec(),
420                    num_qubits: 9,
421                })
422            }
423            Self::Q10(c) => {
424                let result = simulator.run(c)?;
425                Ok(DynamicResult {
426                    amplitudes: result.amplitudes().to_vec(),
427                    num_qubits: 10,
428                })
429            }
430            Self::Q12(c) => {
431                let result = simulator.run(c)?;
432                Ok(DynamicResult {
433                    amplitudes: result.amplitudes().to_vec(),
434                    num_qubits: 12,
435                })
436            }
437            Self::Q16(c) => {
438                let result = simulator.run(c)?;
439                Ok(DynamicResult {
440                    amplitudes: result.amplitudes().to_vec(),
441                    num_qubits: 16,
442                })
443            }
444            Self::Q20(c) => {
445                let result = simulator.run(c)?;
446                Ok(DynamicResult {
447                    amplitudes: result.amplitudes().to_vec(),
448                    num_qubits: 20,
449                })
450            }
451            Self::Q24(c) => {
452                let result = simulator.run(c)?;
453                Ok(DynamicResult {
454                    amplitudes: result.amplitudes().to_vec(),
455                    num_qubits: 24,
456                })
457            }
458            Self::Q32(c) => {
459                let result = simulator.run(c)?;
460                Ok(DynamicResult {
461                    amplitudes: result.amplitudes().to_vec(),
462                    num_qubits: 32,
463                })
464            }
465        }
466    }
467
468    /// Check if GPU acceleration is available
469    #[cfg(all(feature = "gpu", not(target_os = "macos")))]
470    pub fn is_gpu_available() -> bool {
471        GpuStateVectorSimulator::is_available()
472    }
473
474    /// Run the circuit on a GPU simulator
475    #[cfg(all(feature = "gpu", not(target_os = "macos")))]
476    pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
477        // Try to create the GPU simulator
478        let mut gpu_simulator = match GpuStateVectorSimulator::new_blocking() {
479            Ok(sim) => sim,
480            Err(e) => {
481                return Err(QuantRS2Error::BackendExecutionFailed(format!(
482                    "Failed to create GPU simulator: {}",
483                    e
484                )))
485            }
486        };
487
488        // Run the circuit on the GPU
489        match self {
490            DynamicCircuit::Q2(c) => {
491                let result = gpu_simulator.run(c).map_err(|e| {
492                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
493                })?;
494                Ok(DynamicResult {
495                    amplitudes: result.amplitudes.clone(),
496                    num_qubits: 2,
497                })
498            }
499            DynamicCircuit::Q3(c) => {
500                let result = gpu_simulator.run(c).map_err(|e| {
501                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
502                })?;
503                Ok(DynamicResult {
504                    amplitudes: result.amplitudes.clone(),
505                    num_qubits: 3,
506                })
507            }
508            DynamicCircuit::Q4(c) => {
509                let result = gpu_simulator.run(c).map_err(|e| {
510                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
511                })?;
512                Ok(DynamicResult {
513                    amplitudes: result.amplitudes.clone(),
514                    num_qubits: 4,
515                })
516            }
517            DynamicCircuit::Q5(c) => {
518                let result = gpu_simulator.run(c).map_err(|e| {
519                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
520                })?;
521                Ok(DynamicResult {
522                    amplitudes: result.amplitudes.clone(),
523                    num_qubits: 5,
524                })
525            }
526            DynamicCircuit::Q6(c) => {
527                let result = gpu_simulator.run(c).map_err(|e| {
528                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
529                })?;
530                Ok(DynamicResult {
531                    amplitudes: result.amplitudes.clone(),
532                    num_qubits: 6,
533                })
534            }
535            DynamicCircuit::Q7(c) => {
536                let result = gpu_simulator.run(c).map_err(|e| {
537                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
538                })?;
539                Ok(DynamicResult {
540                    amplitudes: result.amplitudes.clone(),
541                    num_qubits: 7,
542                })
543            }
544            DynamicCircuit::Q8(c) => {
545                let result = gpu_simulator.run(c).map_err(|e| {
546                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
547                })?;
548                Ok(DynamicResult {
549                    amplitudes: result.amplitudes.clone(),
550                    num_qubits: 8,
551                })
552            }
553            DynamicCircuit::Q9(c) => {
554                let result = gpu_simulator.run(c).map_err(|e| {
555                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
556                })?;
557                Ok(DynamicResult {
558                    amplitudes: result.amplitudes.clone(),
559                    num_qubits: 9,
560                })
561            }
562            DynamicCircuit::Q10(c) => {
563                let result = gpu_simulator.run(c).map_err(|e| {
564                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
565                })?;
566                Ok(DynamicResult {
567                    amplitudes: result.amplitudes.clone(),
568                    num_qubits: 10,
569                })
570            }
571            DynamicCircuit::Q12(c) => {
572                let result = gpu_simulator.run(c).map_err(|e| {
573                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
574                })?;
575                Ok(DynamicResult {
576                    amplitudes: result.amplitudes.clone(),
577                    num_qubits: 12,
578                })
579            }
580            DynamicCircuit::Q16(c) => {
581                let result = gpu_simulator.run(c).map_err(|e| {
582                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
583                })?;
584                Ok(DynamicResult {
585                    amplitudes: result.amplitudes.clone(),
586                    num_qubits: 16,
587                })
588            }
589            DynamicCircuit::Q20(c) => {
590                let result = gpu_simulator.run(c).map_err(|e| {
591                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
592                })?;
593                Ok(DynamicResult {
594                    amplitudes: result.amplitudes.clone(),
595                    num_qubits: 20,
596                })
597            }
598            DynamicCircuit::Q24(c) => {
599                let result = gpu_simulator.run(c).map_err(|e| {
600                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
601                })?;
602                Ok(DynamicResult {
603                    amplitudes: result.amplitudes.clone(),
604                    num_qubits: 24,
605                })
606            }
607            DynamicCircuit::Q32(c) => {
608                let result = gpu_simulator.run(c).map_err(|e| {
609                    QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
610                })?;
611                Ok(DynamicResult {
612                    amplitudes: result.amplitudes.clone(),
613                    num_qubits: 32,
614                })
615            }
616        }
617    }
618
619    /// Check if GPU acceleration is available (stub for macOS)
620    #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
621    pub const fn is_gpu_available() -> bool {
622        false
623    }
624
625    /// Run the circuit on a GPU simulator (stub for macOS)
626    #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
627    pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
628        Err(QuantRS2Error::BackendExecutionFailed(
629            "GPU acceleration is not available on this platform".to_string(),
630        ))
631    }
632
633    /// Run the circuit on the best available simulator (GPU if available, CPU otherwise)
634    #[cfg(all(feature = "gpu", not(target_os = "macos")))]
635    pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
636        if Self::is_gpu_available() && self.num_qubits() >= 4 {
637            self.run_gpu()
638        } else {
639            let simulator = StateVectorSimulator::new();
640            self.run(&simulator)
641        }
642    }
643
644    /// Run the circuit on the best available simulator (CPU only on macOS with GPU feature)
645    #[cfg(all(feature = "gpu", target_os = "macos"))]
646    pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
647        let simulator = StateVectorSimulator::new();
648        self.run(&simulator)
649    }
650
651    /// Run the circuit on the best available simulator (CPU only if GPU feature is disabled)
652    #[cfg(not(feature = "gpu"))]
653    pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
654        let simulator = StateVectorSimulator::new();
655        self.run(&simulator)
656    }
657}
658
659/// Dynamic simulation result that can handle any qubit count
660pub struct DynamicResult {
661    /// State vector amplitudes
662    pub amplitudes: Vec<Complex64>,
663    /// Number of qubits
664    pub num_qubits: usize,
665}
666
667impl DynamicResult {
668    /// Get the state vector amplitudes
669    pub fn amplitudes(&self) -> &[Complex64] {
670        &self.amplitudes
671    }
672
673    /// Get the probabilities for each basis state
674    pub fn probabilities(&self) -> Vec<f64> {
675        self.amplitudes.iter().map(|amp| amp.norm_sqr()).collect()
676    }
677
678    /// Get the number of qubits
679    pub const fn num_qubits(&self) -> usize {
680        self.num_qubits
681    }
682}