1use crate::simulator::Simulator; use scirs2_core::Complex64;
3use pyo3::exceptions::PyValueError;
4use pyo3::PyResult;
5use quantrs2_circuit::builder::Circuit;
6use quantrs2_circuit::builder::Simulator as CircuitSimulator; use quantrs2_core::{
8 error::{QuantRS2Error, QuantRS2Result},
9 gate::GateOp,
10};
11
12#[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
24pub enum DynamicCircuit {
26 Q2(Circuit<2>),
28 Q3(Circuit<3>),
30 Q4(Circuit<4>),
32 Q5(Circuit<5>),
34 Q6(Circuit<6>),
36 Q7(Circuit<7>),
38 Q8(Circuit<8>),
40 Q9(Circuit<9>),
42 Q10(Circuit<10>),
44 Q12(Circuit<12>),
46 Q16(Circuit<16>),
48 Q20(Circuit<20>),
50 Q24(Circuit<24>),
52 Q32(Circuit<32>),
54}
55
56impl DynamicCircuit {
57 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 pub fn gates(&self) -> Vec<String> {
84 self.get_gate_names()
85 }
86
87 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 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 pub fn get_single_qubit_for_gate(&self, gate_type: &str, index: usize) -> PyResult<u32> {
195 let gate_name = gate_type.to_string();
197 let gates = self.get_gate_names();
198
199 let mut count = 0;
201 for (i, name) in gates.iter().enumerate() {
202 if name == &gate_name {
203 if count == index {
204 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 _ => 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 pub fn get_rotation_params_for_gate(
229 &self,
230 gate_type: &str,
231 index: usize,
232 ) -> PyResult<(u32, f64)> {
233 let gate_name = gate_type.to_string();
235 let gates = self.get_gate_names();
236
237 let mut count = 0;
239 for name in gates.iter() {
240 if name == &gate_name {
241 if count == index {
242 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 pub fn get_two_qubit_params_for_gate(
257 &self,
258 gate_type: &str,
259 index: usize,
260 ) -> PyResult<(u32, u32)> {
261 let gate_name = gate_type.to_string();
263 let gates = self.get_gate_names();
264
265 let mut count = 0;
267 for name in gates.iter() {
268 if name == &gate_name {
269 if count == index {
270 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 pub fn get_controlled_rotation_params_for_gate(
285 &self,
286 gate_type: &str,
287 index: usize,
288 ) -> PyResult<(u32, u32, f64)> {
289 let gate_name = gate_type.to_string();
291 let gates = self.get_gate_names();
292
293 let mut count = 0;
295 for name in gates.iter() {
296 if name == &gate_name {
297 if count == index {
298 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 pub fn get_three_qubit_params_for_gate(
313 &self,
314 gate_type: &str,
315 index: usize,
316 ) -> PyResult<(u32, u32, u32)> {
317 let gate_name = gate_type.to_string();
319 let gates = self.get_gate_names();
320
321 let mut count = 0;
323 for name in gates.iter() {
324 if name == &gate_name {
325 if count == index {
326 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 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 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 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
468 pub fn is_gpu_available() -> bool {
469 GpuStateVectorSimulator::is_available()
470 }
471
472 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
474 pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
475 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 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 #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
619 pub fn is_gpu_available() -> bool {
620 false
621 }
622
623 #[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 #[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 #[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 #[cfg(not(feature = "gpu"))]
651 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
652 let simulator = StateVectorSimulator::new();
653 self.run(&simulator)
654 }
655}
656
657pub struct DynamicResult {
659 pub amplitudes: Vec<Complex64>,
661 pub num_qubits: usize,
663}
664
665impl DynamicResult {
666 pub fn amplitudes(&self) -> &[Complex64] {
668 &self.amplitudes
669 }
670
671 pub fn probabilities(&self) -> Vec<f64> {
673 self.amplitudes.iter().map(|amp| amp.norm_sqr()).collect()
674 }
675
676 pub fn num_qubits(&self) -> usize {
678 self.num_qubits
679 }
680}