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 pub fn gates(&self) -> Vec<String> {
86 self.get_gate_names()
87 }
88
89 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 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 #[cfg(feature = "python")]
197 pub fn get_single_qubit_for_gate(&self, gate_type: &str, index: usize) -> PyResult<u32> {
198 let gate_name = gate_type.to_string();
200 let gates = self.get_gate_names();
201
202 let mut count = 0;
204 for (i, name) in gates.iter().enumerate() {
205 if name == &gate_name {
206 if count == index {
207 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 _ => 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 #[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 let gate_name = gate_type.to_string();
238 let gates = self.get_gate_names();
239
240 let mut count = 0;
242 for name in &gates {
243 if name == &gate_name {
244 if count == index {
245 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 #[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 let gate_name = gate_type.to_string();
266 let gates = self.get_gate_names();
267
268 let mut count = 0;
270 for name in &gates {
271 if name == &gate_name {
272 if count == index {
273 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 #[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 let gate_name = gate_type.to_string();
294 let gates = self.get_gate_names();
295
296 let mut count = 0;
298 for name in &gates {
299 if name == &gate_name {
300 if count == index {
301 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 #[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 let gate_name = gate_type.to_string();
322 let gates = self.get_gate_names();
323
324 let mut count = 0;
326 for name in &gates {
327 if name == &gate_name {
328 if count == index {
329 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 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 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 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
470 pub fn is_gpu_available() -> bool {
471 GpuStateVectorSimulator::is_available()
472 }
473
474 #[cfg(all(feature = "gpu", not(target_os = "macos")))]
476 pub fn run_gpu(&self) -> QuantRS2Result<DynamicResult> {
477 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 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 #[cfg(not(all(feature = "gpu", not(target_os = "macos"))))]
621 pub const fn is_gpu_available() -> bool {
622 false
623 }
624
625 #[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 #[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 #[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 #[cfg(not(feature = "gpu"))]
653 pub fn run_best(&self) -> QuantRS2Result<DynamicResult> {
654 let simulator = StateVectorSimulator::new();
655 self.run(&simulator)
656 }
657}
658
659pub struct DynamicResult {
661 pub amplitudes: Vec<Complex64>,
663 pub num_qubits: usize,
665}
666
667impl DynamicResult {
668 pub fn amplitudes(&self) -> &[Complex64] {
670 &self.amplitudes
671 }
672
673 pub fn probabilities(&self) -> Vec<f64> {
675 self.amplitudes.iter().map(|amp| amp.norm_sqr()).collect()
676 }
677
678 pub const fn num_qubits(&self) -> usize {
680 self.num_qubits
681 }
682}