1use crate::simulator::Simulator; #[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; use quantrs2_core::{
9 error::{QuantRS2Error, QuantRS2Result},
10 gate::GateOp,
11};
12use scirs2_core::Complex64;
13
14#[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
26pub enum DynamicCircuit {
28 Q2(Circuit<2>),
30 Q3(Circuit<3>),
32 Q4(Circuit<4>),
34 Q5(Circuit<5>),
36 Q6(Circuit<6>),
38 Q7(Circuit<7>),
40 Q8(Circuit<8>),
42 Q9(Circuit<9>),
44 Q10(Circuit<10>),
46 Q12(Circuit<12>),
48 Q16(Circuit<16>),
50 Q20(Circuit<20>),
52 Q24(Circuit<24>),
54 Q32(Circuit<32>),
56}
57
58impl DynamicCircuit {
59 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 #[must_use]
86 pub fn gates(&self) -> Vec<String> {
87 self.get_gate_names()
88 }
89
90 #[must_use]
102 pub const fn num_qubits(&self) -> usize {
103 match self {
104 Self::Q2(_) => 2,
105 Self::Q3(_) => 3,
106 Self::Q4(_) => 4,
107 Self::Q5(_) => 5,
108 Self::Q6(_) => 6,
109 Self::Q7(_) => 7,
110 Self::Q8(_) => 8,
111 Self::Q9(_) => 9,
112 Self::Q10(_) => 10,
113 Self::Q12(_) => 12,
114 Self::Q16(_) => 16,
115 Self::Q20(_) => 20,
116 Self::Q24(_) => 24,
117 Self::Q32(_) => 32,
118 }
119 }
120
121 #[must_use]
123 pub fn get_gate_names(&self) -> Vec<String> {
124 match self {
125 Self::Q2(c) => c
126 .gates()
127 .iter()
128 .map(|gate| gate.name().to_string())
129 .collect(),
130 Self::Q3(c) => c
131 .gates()
132 .iter()
133 .map(|gate| gate.name().to_string())
134 .collect(),
135 Self::Q4(c) => c
136 .gates()
137 .iter()
138 .map(|gate| gate.name().to_string())
139 .collect(),
140 Self::Q5(c) => c
141 .gates()
142 .iter()
143 .map(|gate| gate.name().to_string())
144 .collect(),
145 Self::Q6(c) => c
146 .gates()
147 .iter()
148 .map(|gate| gate.name().to_string())
149 .collect(),
150 Self::Q7(c) => c
151 .gates()
152 .iter()
153 .map(|gate| gate.name().to_string())
154 .collect(),
155 Self::Q8(c) => c
156 .gates()
157 .iter()
158 .map(|gate| gate.name().to_string())
159 .collect(),
160 Self::Q9(c) => c
161 .gates()
162 .iter()
163 .map(|gate| gate.name().to_string())
164 .collect(),
165 Self::Q10(c) => c
166 .gates()
167 .iter()
168 .map(|gate| gate.name().to_string())
169 .collect(),
170 Self::Q12(c) => c
171 .gates()
172 .iter()
173 .map(|gate| gate.name().to_string())
174 .collect(),
175 Self::Q16(c) => c
176 .gates()
177 .iter()
178 .map(|gate| gate.name().to_string())
179 .collect(),
180 Self::Q20(c) => c
181 .gates()
182 .iter()
183 .map(|gate| gate.name().to_string())
184 .collect(),
185 Self::Q24(c) => c
186 .gates()
187 .iter()
188 .map(|gate| gate.name().to_string())
189 .collect(),
190 Self::Q32(c) => c
191 .gates()
192 .iter()
193 .map(|gate| gate.name().to_string())
194 .collect(),
195 }
196 }
197
198 #[cfg(feature = "python")]
200 pub fn get_single_qubit_for_gate(&self, gate_type: &str, index: usize) -> PyResult<u32> {
201 let gate_name = gate_type.to_string();
203 let gates = self.get_gate_names();
204
205 let mut count = 0;
207 for (i, name) in gates.iter().enumerate() {
208 if name == &gate_name {
209 if count == index {
210 match self {
212 Self::Q2(c) => {
213 if let Some(gate) = c.gates().get(i) {
214 if gate.qubits().len() == 1 {
215 return Ok(gate.qubits()[0].id());
216 }
217 }
218 }
219 _ => return Ok(0),
221 }
222 }
223 count += 1;
224 }
225 }
226
227 Err(PyValueError::new_err(format!(
228 "Gate {gate_type} at index {index} not found"
229 )))
230 }
231
232 #[cfg(feature = "python")]
234 pub fn get_rotation_params_for_gate(
235 &self,
236 gate_type: &str,
237 index: usize,
238 ) -> PyResult<(u32, f64)> {
239 let gate_name = gate_type.to_string();
241 let gates = self.get_gate_names();
242
243 let mut count = 0;
245 for name in &gates {
246 if name == &gate_name {
247 if count == index {
248 return Ok((0, 0.0));
250 }
251 count += 1;
252 }
253 }
254
255 Err(PyValueError::new_err(format!(
256 "Gate {gate_type} at index {index} not found"
257 )))
258 }
259
260 #[cfg(feature = "python")]
262 pub fn get_two_qubit_params_for_gate(
263 &self,
264 gate_type: &str,
265 index: usize,
266 ) -> PyResult<(u32, u32)> {
267 let gate_name = gate_type.to_string();
269 let gates = self.get_gate_names();
270
271 let mut count = 0;
273 for name in &gates {
274 if name == &gate_name {
275 if count == index {
276 return Ok((0, 1));
278 }
279 count += 1;
280 }
281 }
282
283 Err(PyValueError::new_err(format!(
284 "Gate {gate_type} at index {index} not found"
285 )))
286 }
287
288 #[cfg(feature = "python")]
290 pub fn get_controlled_rotation_params_for_gate(
291 &self,
292 gate_type: &str,
293 index: usize,
294 ) -> PyResult<(u32, u32, f64)> {
295 let gate_name = gate_type.to_string();
297 let gates = self.get_gate_names();
298
299 let mut count = 0;
301 for name in &gates {
302 if name == &gate_name {
303 if count == index {
304 return Ok((0, 1, 0.0));
306 }
307 count += 1;
308 }
309 }
310
311 Err(PyValueError::new_err(format!(
312 "Gate {gate_type} at index {index} not found"
313 )))
314 }
315
316 #[cfg(feature = "python")]
318 pub fn get_three_qubit_params_for_gate(
319 &self,
320 gate_type: &str,
321 index: usize,
322 ) -> PyResult<(u32, u32, u32)> {
323 let gate_name = gate_type.to_string();
325 let gates = self.get_gate_names();
326
327 let mut count = 0;
329 for name in &gates {
330 if name == &gate_name {
331 if count == index {
332 return Ok((0, 1, 2));
334 }
335 count += 1;
336 }
337 }
338
339 Err(PyValueError::new_err(format!(
340 "Gate {gate_type} at index {index} not found"
341 )))
342 }
343
344 pub fn apply_gate<G: GateOp + Clone + Send + Sync + 'static>(
346 &mut self,
347 gate: G,
348 ) -> QuantRS2Result<()> {
349 match self {
350 Self::Q2(c) => c.add_gate(gate).map(|_| ()),
351 Self::Q3(c) => c.add_gate(gate).map(|_| ()),
352 Self::Q4(c) => c.add_gate(gate).map(|_| ()),
353 Self::Q5(c) => c.add_gate(gate).map(|_| ()),
354 Self::Q6(c) => c.add_gate(gate).map(|_| ()),
355 Self::Q7(c) => c.add_gate(gate).map(|_| ()),
356 Self::Q8(c) => c.add_gate(gate).map(|_| ()),
357 Self::Q9(c) => c.add_gate(gate).map(|_| ()),
358 Self::Q10(c) => c.add_gate(gate).map(|_| ()),
359 Self::Q12(c) => c.add_gate(gate).map(|_| ()),
360 Self::Q16(c) => c.add_gate(gate).map(|_| ()),
361 Self::Q20(c) => c.add_gate(gate).map(|_| ()),
362 Self::Q24(c) => c.add_gate(gate).map(|_| ()),
363 Self::Q32(c) => c.add_gate(gate).map(|_| ()),
364 }
365 }
366
367 pub fn run(&self, simulator: &StateVectorSimulator) -> QuantRS2Result<DynamicResult> {
369 match self {
370 Self::Q2(c) => {
371 let result = simulator.run(c)?;
372 Ok(DynamicResult {
373 amplitudes: result.amplitudes().to_vec(),
374 num_qubits: 2,
375 })
376 }
377 Self::Q3(c) => {
378 let result = simulator.run(c)?;
379 Ok(DynamicResult {
380 amplitudes: result.amplitudes().to_vec(),
381 num_qubits: 3,
382 })
383 }
384 Self::Q4(c) => {
385 let result = simulator.run(c)?;
386 Ok(DynamicResult {
387 amplitudes: result.amplitudes().to_vec(),
388 num_qubits: 4,
389 })
390 }
391 Self::Q5(c) => {
392 let result = simulator.run(c)?;
393 Ok(DynamicResult {
394 amplitudes: result.amplitudes().to_vec(),
395 num_qubits: 5,
396 })
397 }
398 Self::Q6(c) => {
399 let result = simulator.run(c)?;
400 Ok(DynamicResult {
401 amplitudes: result.amplitudes().to_vec(),
402 num_qubits: 6,
403 })
404 }
405 Self::Q7(c) => {
406 let result = simulator.run(c)?;
407 Ok(DynamicResult {
408 amplitudes: result.amplitudes().to_vec(),
409 num_qubits: 7,
410 })
411 }
412 Self::Q8(c) => {
413 let result = simulator.run(c)?;
414 Ok(DynamicResult {
415 amplitudes: result.amplitudes().to_vec(),
416 num_qubits: 8,
417 })
418 }
419 Self::Q9(c) => {
420 let result = simulator.run(c)?;
421 Ok(DynamicResult {
422 amplitudes: result.amplitudes().to_vec(),
423 num_qubits: 9,
424 })
425 }
426 Self::Q10(c) => {
427 let result = simulator.run(c)?;
428 Ok(DynamicResult {
429 amplitudes: result.amplitudes().to_vec(),
430 num_qubits: 10,
431 })
432 }
433 Self::Q12(c) => {
434 let result = simulator.run(c)?;
435 Ok(DynamicResult {
436 amplitudes: result.amplitudes().to_vec(),
437 num_qubits: 12,
438 })
439 }
440 Self::Q16(c) => {
441 let result = simulator.run(c)?;
442 Ok(DynamicResult {
443 amplitudes: result.amplitudes().to_vec(),
444 num_qubits: 16,
445 })
446 }
447 Self::Q20(c) => {
448 let result = simulator.run(c)?;
449 Ok(DynamicResult {
450 amplitudes: result.amplitudes().to_vec(),
451 num_qubits: 20,
452 })
453 }
454 Self::Q24(c) => {
455 let result = simulator.run(c)?;
456 Ok(DynamicResult {
457 amplitudes: result.amplitudes().to_vec(),
458 num_qubits: 24,
459 })
460 }
461 Self::Q32(c) => {
462 let result = simulator.run(c)?;
463 Ok(DynamicResult {
464 amplitudes: result.amplitudes().to_vec(),
465 num_qubits: 32,
466 })
467 }
468 }
469 }
470
471 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
473 pub fn is_gpu_available() -> bool {
474 GpuStateVectorSimulator::is_available()
475 }
476
477 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
479 pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
480 let mut gpu_simulator = match GpuStateVectorSimulator::new_blocking() {
482 Ok(sim) => sim,
483 Err(e) => {
484 return Err(QuantRS2Error::BackendExecutionFailed(format!(
485 "Failed to create GPU simulator: {}",
486 e
487 )))
488 }
489 };
490
491 match self {
493 DynamicCircuit::Q2(c) => {
494 let result = gpu_simulator.run(c).map_err(|e| {
495 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
496 })?;
497 Ok(DynamicResult {
498 amplitudes: result.amplitudes.clone(),
499 num_qubits: 2,
500 })
501 }
502 DynamicCircuit::Q3(c) => {
503 let result = gpu_simulator.run(c).map_err(|e| {
504 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
505 })?;
506 Ok(DynamicResult {
507 amplitudes: result.amplitudes.clone(),
508 num_qubits: 3,
509 })
510 }
511 DynamicCircuit::Q4(c) => {
512 let result = gpu_simulator.run(c).map_err(|e| {
513 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
514 })?;
515 Ok(DynamicResult {
516 amplitudes: result.amplitudes.clone(),
517 num_qubits: 4,
518 })
519 }
520 DynamicCircuit::Q5(c) => {
521 let result = gpu_simulator.run(c).map_err(|e| {
522 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
523 })?;
524 Ok(DynamicResult {
525 amplitudes: result.amplitudes.clone(),
526 num_qubits: 5,
527 })
528 }
529 DynamicCircuit::Q6(c) => {
530 let result = gpu_simulator.run(c).map_err(|e| {
531 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
532 })?;
533 Ok(DynamicResult {
534 amplitudes: result.amplitudes.clone(),
535 num_qubits: 6,
536 })
537 }
538 DynamicCircuit::Q7(c) => {
539 let result = gpu_simulator.run(c).map_err(|e| {
540 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
541 })?;
542 Ok(DynamicResult {
543 amplitudes: result.amplitudes.clone(),
544 num_qubits: 7,
545 })
546 }
547 DynamicCircuit::Q8(c) => {
548 let result = gpu_simulator.run(c).map_err(|e| {
549 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
550 })?;
551 Ok(DynamicResult {
552 amplitudes: result.amplitudes.clone(),
553 num_qubits: 8,
554 })
555 }
556 DynamicCircuit::Q9(c) => {
557 let result = gpu_simulator.run(c).map_err(|e| {
558 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
559 })?;
560 Ok(DynamicResult {
561 amplitudes: result.amplitudes.clone(),
562 num_qubits: 9,
563 })
564 }
565 DynamicCircuit::Q10(c) => {
566 let result = gpu_simulator.run(c).map_err(|e| {
567 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
568 })?;
569 Ok(DynamicResult {
570 amplitudes: result.amplitudes.clone(),
571 num_qubits: 10,
572 })
573 }
574 DynamicCircuit::Q12(c) => {
575 let result = gpu_simulator.run(c).map_err(|e| {
576 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
577 })?;
578 Ok(DynamicResult {
579 amplitudes: result.amplitudes.clone(),
580 num_qubits: 12,
581 })
582 }
583 DynamicCircuit::Q16(c) => {
584 let result = gpu_simulator.run(c).map_err(|e| {
585 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
586 })?;
587 Ok(DynamicResult {
588 amplitudes: result.amplitudes.clone(),
589 num_qubits: 16,
590 })
591 }
592 DynamicCircuit::Q20(c) => {
593 let result = gpu_simulator.run(c).map_err(|e| {
594 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
595 })?;
596 Ok(DynamicResult {
597 amplitudes: result.amplitudes.clone(),
598 num_qubits: 20,
599 })
600 }
601 DynamicCircuit::Q24(c) => {
602 let result = gpu_simulator.run(c).map_err(|e| {
603 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
604 })?;
605 Ok(DynamicResult {
606 amplitudes: result.amplitudes.clone(),
607 num_qubits: 24,
608 })
609 }
610 DynamicCircuit::Q32(c) => {
611 let result = gpu_simulator.run(c).map_err(|e| {
612 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
613 })?;
614 Ok(DynamicResult {
615 amplitudes: result.amplitudes.clone(),
616 num_qubits: 32,
617 })
618 }
619 }
620 }
621
622 #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
624 #[must_use]
625 pub const fn is_gpu_available() -> bool {
626 false
627 }
628
629 #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
631 pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
632 Err(QuantRS2Error::BackendExecutionFailed(
633 "GPU acceleration is not available on this platform".to_string(),
634 ))
635 }
636
637 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
639 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
640 if Self::is_gpu_available() && self.num_qubits() >= 4 {
641 self.run_gpu()
642 } else {
643 let simulator = StateVectorSimulator::new();
644 self.run(&simulator)
645 }
646 }
647
648 #[cfg(all(feature = "gpu", target_os = "macos"))]
650 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
651 let simulator = StateVectorSimulator::new();
652 self.run(&simulator)
653 }
654
655 #[cfg(not(feature = "gpu"))]
657 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
658 let simulator = StateVectorSimulator::new();
659 self.run(&simulator)
660 }
661}
662
663pub struct DynamicResult {
665 pub amplitudes: Vec<Complex64>,
667 pub num_qubits: usize,
669}
670
671impl DynamicResult {
672 #[must_use]
674 pub fn amplitudes(&self) -> &[Complex64] {
675 &self.amplitudes
676 }
677
678 #[must_use]
680 pub fn probabilities(&self) -> Vec<f64> {
681 self.amplitudes
682 .iter()
683 .map(scirs2_core::Complex::norm_sqr)
684 .collect()
685 }
686
687 #[must_use]
689 pub const fn num_qubits(&self) -> usize {
690 self.num_qubits
691 }
692}