quantrs2_sim/
dynamic.rs

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