1use crate::simulator::Simulator; #[cfg(feature = "python")]
9use pyo3::exceptions::PyValueError;
10#[cfg(feature = "python")]
11use pyo3::PyResult;
12use quantrs2_circuit::builder::Circuit;
13use quantrs2_circuit::builder::Simulator as CircuitSimulator; use quantrs2_core::{
15 error::{QuantRS2Error, QuantRS2Result},
16 gate::GateOp,
17};
18use scirs2_core::Complex64;
19
20#[allow(unused_imports)]
22use crate::simulator::SimulatorResult;
23use crate::statevector::StateVectorSimulator;
24#[allow(unused_imports)]
25use quantrs2_core::qubit::QubitId;
26#[allow(unused_imports)]
27use std::collections::HashMap;
28
29#[cfg(all(feature = "gpu", not(target_os = "macos")))]
30use crate::gpu::GpuStateVectorSimulator;
31
32pub enum DynamicCircuit {
55 Q2(Circuit<2>),
57 Q3(Circuit<3>),
59 Q4(Circuit<4>),
61 Q5(Circuit<5>),
63 Q6(Circuit<6>),
65 Q7(Circuit<7>),
67 Q8(Circuit<8>),
69 Q9(Circuit<9>),
71 Q10(Circuit<10>),
73 Q12(Circuit<12>),
75 Q16(Circuit<16>),
77 Q20(Circuit<20>),
79 Q24(Circuit<24>),
81 Q32(Circuit<32>),
83}
84
85impl DynamicCircuit {
86 pub fn new(n_qubits: usize) -> QuantRS2Result<Self> {
88 match n_qubits {
89 2 => Ok(Self::Q2(Circuit::<2>::new())),
90 3 => Ok(Self::Q3(Circuit::<3>::new())),
91 4 => Ok(Self::Q4(Circuit::<4>::new())),
92 5 => Ok(Self::Q5(Circuit::<5>::new())),
93 6 => Ok(Self::Q6(Circuit::<6>::new())),
94 7 => Ok(Self::Q7(Circuit::<7>::new())),
95 8 => Ok(Self::Q8(Circuit::<8>::new())),
96 9 => Ok(Self::Q9(Circuit::<9>::new())),
97 10 => Ok(Self::Q10(Circuit::<10>::new())),
98 12 => Ok(Self::Q12(Circuit::<12>::new())),
99 16 => Ok(Self::Q16(Circuit::<16>::new())),
100 20 => Ok(Self::Q20(Circuit::<20>::new())),
101 24 => Ok(Self::Q24(Circuit::<24>::new())),
102 32 => Ok(Self::Q32(Circuit::<32>::new())),
103 _ => Err(QuantRS2Error::UnsupportedQubits(
104 n_qubits,
105 "Supported qubit counts are 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16, 20, 24, and 32."
106 .to_string(),
107 )),
108 }
109 }
110
111 #[must_use]
113 pub fn gates(&self) -> Vec<String> {
114 self.get_gate_names()
115 }
116
117 #[must_use]
129 pub const fn num_qubits(&self) -> usize {
130 match self {
131 Self::Q2(_) => 2,
132 Self::Q3(_) => 3,
133 Self::Q4(_) => 4,
134 Self::Q5(_) => 5,
135 Self::Q6(_) => 6,
136 Self::Q7(_) => 7,
137 Self::Q8(_) => 8,
138 Self::Q9(_) => 9,
139 Self::Q10(_) => 10,
140 Self::Q12(_) => 12,
141 Self::Q16(_) => 16,
142 Self::Q20(_) => 20,
143 Self::Q24(_) => 24,
144 Self::Q32(_) => 32,
145 }
146 }
147
148 #[must_use]
150 pub fn get_gate_names(&self) -> Vec<String> {
151 match self {
152 Self::Q2(c) => c
153 .gates()
154 .iter()
155 .map(|gate| gate.name().to_string())
156 .collect(),
157 Self::Q3(c) => c
158 .gates()
159 .iter()
160 .map(|gate| gate.name().to_string())
161 .collect(),
162 Self::Q4(c) => c
163 .gates()
164 .iter()
165 .map(|gate| gate.name().to_string())
166 .collect(),
167 Self::Q5(c) => c
168 .gates()
169 .iter()
170 .map(|gate| gate.name().to_string())
171 .collect(),
172 Self::Q6(c) => c
173 .gates()
174 .iter()
175 .map(|gate| gate.name().to_string())
176 .collect(),
177 Self::Q7(c) => c
178 .gates()
179 .iter()
180 .map(|gate| gate.name().to_string())
181 .collect(),
182 Self::Q8(c) => c
183 .gates()
184 .iter()
185 .map(|gate| gate.name().to_string())
186 .collect(),
187 Self::Q9(c) => c
188 .gates()
189 .iter()
190 .map(|gate| gate.name().to_string())
191 .collect(),
192 Self::Q10(c) => c
193 .gates()
194 .iter()
195 .map(|gate| gate.name().to_string())
196 .collect(),
197 Self::Q12(c) => c
198 .gates()
199 .iter()
200 .map(|gate| gate.name().to_string())
201 .collect(),
202 Self::Q16(c) => c
203 .gates()
204 .iter()
205 .map(|gate| gate.name().to_string())
206 .collect(),
207 Self::Q20(c) => c
208 .gates()
209 .iter()
210 .map(|gate| gate.name().to_string())
211 .collect(),
212 Self::Q24(c) => c
213 .gates()
214 .iter()
215 .map(|gate| gate.name().to_string())
216 .collect(),
217 Self::Q32(c) => c
218 .gates()
219 .iter()
220 .map(|gate| gate.name().to_string())
221 .collect(),
222 }
223 }
224
225 #[cfg(feature = "python")]
227 pub fn get_single_qubit_for_gate(&self, gate_type: &str, index: usize) -> PyResult<u32> {
228 let gate_name = gate_type.to_string();
230 let gates = self.get_gate_names();
231
232 let mut count = 0;
234 for (i, name) in gates.iter().enumerate() {
235 if name == &gate_name {
236 if count == index {
237 match self {
239 Self::Q2(c) => {
240 if let Some(gate) = c.gates().get(i) {
241 if gate.qubits().len() == 1 {
242 return Ok(gate.qubits()[0].id());
243 }
244 }
245 }
246 _ => return Ok(0),
248 }
249 }
250 count += 1;
251 }
252 }
253
254 Err(PyValueError::new_err(format!(
255 "Gate {gate_type} at index {index} not found"
256 )))
257 }
258
259 #[cfg(feature = "python")]
261 pub fn get_rotation_params_for_gate(
262 &self,
263 gate_type: &str,
264 index: usize,
265 ) -> PyResult<(u32, f64)> {
266 let gate_name = gate_type.to_string();
268 let gates = self.get_gate_names();
269
270 let mut count = 0;
272 for name in &gates {
273 if name == &gate_name {
274 if count == index {
275 return Ok((0, 0.0));
277 }
278 count += 1;
279 }
280 }
281
282 Err(PyValueError::new_err(format!(
283 "Gate {gate_type} at index {index} not found"
284 )))
285 }
286
287 #[cfg(feature = "python")]
289 pub fn get_two_qubit_params_for_gate(
290 &self,
291 gate_type: &str,
292 index: usize,
293 ) -> PyResult<(u32, u32)> {
294 let gate_name = gate_type.to_string();
296 let gates = self.get_gate_names();
297
298 let mut count = 0;
300 for name in &gates {
301 if name == &gate_name {
302 if count == index {
303 return Ok((0, 1));
305 }
306 count += 1;
307 }
308 }
309
310 Err(PyValueError::new_err(format!(
311 "Gate {gate_type} at index {index} not found"
312 )))
313 }
314
315 #[cfg(feature = "python")]
317 pub fn get_controlled_rotation_params_for_gate(
318 &self,
319 gate_type: &str,
320 index: usize,
321 ) -> PyResult<(u32, u32, f64)> {
322 let gate_name = gate_type.to_string();
324 let gates = self.get_gate_names();
325
326 let mut count = 0;
328 for name in &gates {
329 if name == &gate_name {
330 if count == index {
331 return Ok((0, 1, 0.0));
333 }
334 count += 1;
335 }
336 }
337
338 Err(PyValueError::new_err(format!(
339 "Gate {gate_type} at index {index} not found"
340 )))
341 }
342
343 #[cfg(feature = "python")]
345 pub fn get_three_qubit_params_for_gate(
346 &self,
347 gate_type: &str,
348 index: usize,
349 ) -> PyResult<(u32, u32, u32)> {
350 let gate_name = gate_type.to_string();
352 let gates = self.get_gate_names();
353
354 let mut count = 0;
356 for name in &gates {
357 if name == &gate_name {
358 if count == index {
359 return Ok((0, 1, 2));
361 }
362 count += 1;
363 }
364 }
365
366 Err(PyValueError::new_err(format!(
367 "Gate {gate_type} at index {index} not found"
368 )))
369 }
370
371 pub fn apply_gate<G: GateOp + Clone + Send + Sync + 'static>(
373 &mut self,
374 gate: G,
375 ) -> QuantRS2Result<()> {
376 match self {
377 Self::Q2(c) => c.add_gate(gate).map(|_| ()),
378 Self::Q3(c) => c.add_gate(gate).map(|_| ()),
379 Self::Q4(c) => c.add_gate(gate).map(|_| ()),
380 Self::Q5(c) => c.add_gate(gate).map(|_| ()),
381 Self::Q6(c) => c.add_gate(gate).map(|_| ()),
382 Self::Q7(c) => c.add_gate(gate).map(|_| ()),
383 Self::Q8(c) => c.add_gate(gate).map(|_| ()),
384 Self::Q9(c) => c.add_gate(gate).map(|_| ()),
385 Self::Q10(c) => c.add_gate(gate).map(|_| ()),
386 Self::Q12(c) => c.add_gate(gate).map(|_| ()),
387 Self::Q16(c) => c.add_gate(gate).map(|_| ()),
388 Self::Q20(c) => c.add_gate(gate).map(|_| ()),
389 Self::Q24(c) => c.add_gate(gate).map(|_| ()),
390 Self::Q32(c) => c.add_gate(gate).map(|_| ()),
391 }
392 }
393
394 pub fn run(&self, simulator: &StateVectorSimulator) -> QuantRS2Result<DynamicResult> {
396 match self {
397 Self::Q2(c) => {
398 let result = simulator.run(c)?;
399 Ok(DynamicResult {
400 amplitudes: result.amplitudes().to_vec(),
401 num_qubits: 2,
402 })
403 }
404 Self::Q3(c) => {
405 let result = simulator.run(c)?;
406 Ok(DynamicResult {
407 amplitudes: result.amplitudes().to_vec(),
408 num_qubits: 3,
409 })
410 }
411 Self::Q4(c) => {
412 let result = simulator.run(c)?;
413 Ok(DynamicResult {
414 amplitudes: result.amplitudes().to_vec(),
415 num_qubits: 4,
416 })
417 }
418 Self::Q5(c) => {
419 let result = simulator.run(c)?;
420 Ok(DynamicResult {
421 amplitudes: result.amplitudes().to_vec(),
422 num_qubits: 5,
423 })
424 }
425 Self::Q6(c) => {
426 let result = simulator.run(c)?;
427 Ok(DynamicResult {
428 amplitudes: result.amplitudes().to_vec(),
429 num_qubits: 6,
430 })
431 }
432 Self::Q7(c) => {
433 let result = simulator.run(c)?;
434 Ok(DynamicResult {
435 amplitudes: result.amplitudes().to_vec(),
436 num_qubits: 7,
437 })
438 }
439 Self::Q8(c) => {
440 let result = simulator.run(c)?;
441 Ok(DynamicResult {
442 amplitudes: result.amplitudes().to_vec(),
443 num_qubits: 8,
444 })
445 }
446 Self::Q9(c) => {
447 let result = simulator.run(c)?;
448 Ok(DynamicResult {
449 amplitudes: result.amplitudes().to_vec(),
450 num_qubits: 9,
451 })
452 }
453 Self::Q10(c) => {
454 let result = simulator.run(c)?;
455 Ok(DynamicResult {
456 amplitudes: result.amplitudes().to_vec(),
457 num_qubits: 10,
458 })
459 }
460 Self::Q12(c) => {
461 let result = simulator.run(c)?;
462 Ok(DynamicResult {
463 amplitudes: result.amplitudes().to_vec(),
464 num_qubits: 12,
465 })
466 }
467 Self::Q16(c) => {
468 let result = simulator.run(c)?;
469 Ok(DynamicResult {
470 amplitudes: result.amplitudes().to_vec(),
471 num_qubits: 16,
472 })
473 }
474 Self::Q20(c) => {
475 let result = simulator.run(c)?;
476 Ok(DynamicResult {
477 amplitudes: result.amplitudes().to_vec(),
478 num_qubits: 20,
479 })
480 }
481 Self::Q24(c) => {
482 let result = simulator.run(c)?;
483 Ok(DynamicResult {
484 amplitudes: result.amplitudes().to_vec(),
485 num_qubits: 24,
486 })
487 }
488 Self::Q32(c) => {
489 let result = simulator.run(c)?;
490 Ok(DynamicResult {
491 amplitudes: result.amplitudes().to_vec(),
492 num_qubits: 32,
493 })
494 }
495 }
496 }
497
498 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
500 pub fn is_gpu_available() -> bool {
501 GpuStateVectorSimulator::is_available()
502 }
503
504 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
506 pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
507 let mut gpu_simulator = match GpuStateVectorSimulator::new_blocking() {
509 Ok(sim) => sim,
510 Err(e) => {
511 return Err(QuantRS2Error::BackendExecutionFailed(format!(
512 "Failed to create GPU simulator: {}",
513 e
514 )))
515 }
516 };
517
518 match self {
520 DynamicCircuit::Q2(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: 2,
527 })
528 }
529 DynamicCircuit::Q3(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: 3,
536 })
537 }
538 DynamicCircuit::Q4(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: 4,
545 })
546 }
547 DynamicCircuit::Q5(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: 5,
554 })
555 }
556 DynamicCircuit::Q6(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: 6,
563 })
564 }
565 DynamicCircuit::Q7(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: 7,
572 })
573 }
574 DynamicCircuit::Q8(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: 8,
581 })
582 }
583 DynamicCircuit::Q9(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: 9,
590 })
591 }
592 DynamicCircuit::Q10(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: 10,
599 })
600 }
601 DynamicCircuit::Q12(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: 12,
608 })
609 }
610 DynamicCircuit::Q16(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: 16,
617 })
618 }
619 DynamicCircuit::Q20(c) => {
620 let result = gpu_simulator.run(c).map_err(|e| {
621 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
622 })?;
623 Ok(DynamicResult {
624 amplitudes: result.amplitudes.clone(),
625 num_qubits: 20,
626 })
627 }
628 DynamicCircuit::Q24(c) => {
629 let result = gpu_simulator.run(c).map_err(|e| {
630 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
631 })?;
632 Ok(DynamicResult {
633 amplitudes: result.amplitudes.clone(),
634 num_qubits: 24,
635 })
636 }
637 DynamicCircuit::Q32(c) => {
638 let result = gpu_simulator.run(c).map_err(|e| {
639 QuantRS2Error::BackendExecutionFailed(format!("GPU simulation failed: {}", e))
640 })?;
641 Ok(DynamicResult {
642 amplitudes: result.amplitudes.clone(),
643 num_qubits: 32,
644 })
645 }
646 }
647 }
648
649 #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
651 #[must_use]
652 pub const fn is_gpu_available() -> bool {
653 false
654 }
655
656 #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
658 pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
659 Err(QuantRS2Error::BackendExecutionFailed(
660 "GPU acceleration is not available on this platform".to_string(),
661 ))
662 }
663
664 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
666 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
667 if Self::is_gpu_available() && self.num_qubits() >= 4 {
668 self.run_gpu()
669 } else {
670 let simulator = StateVectorSimulator::new();
671 self.run(&simulator)
672 }
673 }
674
675 #[cfg(all(feature = "gpu", target_os = "macos"))]
677 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
678 let simulator = StateVectorSimulator::new();
679 self.run(&simulator)
680 }
681
682 #[cfg(not(feature = "gpu"))]
684 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
685 let simulator = StateVectorSimulator::new();
686 self.run(&simulator)
687 }
688}
689
690pub struct DynamicResult {
692 pub amplitudes: Vec<Complex64>,
694 pub num_qubits: usize,
696}
697
698impl DynamicResult {
699 #[must_use]
701 pub fn amplitudes(&self) -> &[Complex64] {
702 &self.amplitudes
703 }
704
705 #[must_use]
707 pub fn probabilities(&self) -> Vec<f64> {
708 self.amplitudes
709 .iter()
710 .map(scirs2_core::Complex::norm_sqr)
711 .collect()
712 }
713
714 #[must_use]
716 pub const fn num_qubits(&self) -> usize {
717 self.num_qubits
718 }
719}