1use crate::compiler::compilable::Compilable;
2#[cfg(feature = "gpu")]
3use crate::components::gpu_context::GpuKernelArgs;
4#[cfg(feature = "gpu")]
5use crate::components::gpu_context::{GPU_CONTEXT, KernelType};
6use crate::{components::{state::State, pauli_string::PauliString}, errors::Error};
7use dyn_clone::DynClone;
8use num_complex::Complex;
9#[cfg(feature = "gpu")]
10use ocl::prm::Float2;
11use rayon::prelude::*;
12#[cfg(feature = "gpu")]
13use std::f64::consts::PI;
14use std::fmt::Display;
15use std::{collections::HashSet, fmt::Debug};
16
17const PARALLEL_THRESHOLD_NUM_QUBITS: usize = 10;
19
20const OPENCL_THRESHOLD_NUM_QUBITS: usize = 15;
22
23#[cfg(feature = "gpu")]
24fn execute_on_gpu(
25 state: &State,
26 target_qubit: usize,
27 control_qubits: &[usize],
28 kernel_type: KernelType,
29 global_work_size: usize,
30 kernel_args: GpuKernelArgs,
31) -> Result<Vec<Complex<f64>>, Error> {
32 let mut context_guard = GPU_CONTEXT.lock().map_err(|_| Error::GpuContextLockError)?;
33 let context = match *context_guard {
34 Ok(ref mut ctx) => ctx,
35 Err(ref e) => return Err(e.clone()), };
37
38 let num_qubits = state.num_qubits();
39 let num_state_elements = state.state_vector.len();
40
41 let state_buffer_cloned = context.ensure_state_buffer(num_state_elements)?.clone();
43
44 let control_qubits_i32: Vec<i32> = control_qubits.iter().map(|&q| q as i32).collect();
45 let control_buffer_len = control_qubits_i32.len();
46 let control_buffer_cloned = context.ensure_control_buffer(control_buffer_len)?.clone();
47
48 let state_vector_f32: Vec<Float2> = state
49 .state_vector
50 .iter()
51 .map(|c| Float2::new(c.re as f32, c.im as f32))
52 .collect();
53
54 state_buffer_cloned
56 .write(&state_vector_f32)
57 .enq()
58 .map_err(|e| Error::OpenCLError(format!("Failed to write to state buffer: {}", e)))?;
59
60 if !control_qubits_i32.is_empty() {
61 control_buffer_cloned
62 .write(&control_qubits_i32)
63 .enq()
64 .map_err(|e| Error::OpenCLError(format!("Failed to write to control buffer: {}", e)))?;
65 } else {
66 let dummy_control_data = vec![0; 1]; control_buffer_cloned
69 .write(&dummy_control_data)
70 .enq()
71 .map_err(|e| {
72 Error::OpenCLError(format!("Failed to write to dummy control buffer: {}", e))
73 })?;
74 }
75
76 let mut kernel_builder = context.pro_que.kernel_builder(kernel_type.name());
77 kernel_builder
78 .global_work_size(global_work_size)
79 .arg(&state_buffer_cloned) .arg(num_qubits as i32)
81 .arg(target_qubit as i32)
82 .arg(control_buffer_cloned)
83 .arg(control_qubits_i32.len() as i32);
84
85 match kernel_args {
86 GpuKernelArgs::None => {
87 }
89 GpuKernelArgs::SOrSdag { sign } => {
90 kernel_builder.arg(sign);
91 }
92 GpuKernelArgs::PhaseShift {
93 cos_angle,
94 sin_angle,
95 } => {
96 kernel_builder.arg(cos_angle).arg(sin_angle);
97 }
98 GpuKernelArgs::SwapTarget { q1 } => {
99 kernel_builder.arg(q1);
100 }
101 GpuKernelArgs::RotationGate {
102 cos_half_angle,
103 sin_half_angle,
104 } => {
105 kernel_builder.arg(cos_half_angle).arg(sin_half_angle);
106 }
107 GpuKernelArgs::Matchgate {
108 q1,
109 cos_theta_half,
110 sin_theta_half,
111 exp_i_phi1,
112 exp_i_phi2,
113 } => {
114 kernel_builder
115 .arg(q1)
116 .arg(cos_theta_half)
117 .arg(sin_theta_half)
118 .arg(exp_i_phi1)
119 .arg(exp_i_phi2);
120 }
121 }
122
123 let kernel = kernel_builder.build().map_err(|e| {
124 Error::OpenCLError(format!(
125 "Failed to build kernel '{}': {}",
126 kernel_type.name(),
127 e
128 ))
129 })?;
130
131 unsafe {
132 kernel
133 .enq()
134 .map_err(|e| Error::OpenCLError(format!("Failed to enqueue kernel: {}", e)))?;
135 }
136
137 let mut state_vector_ocl_result = vec![Float2::new(0.0, 0.0); num_state_elements];
138 state_buffer_cloned
140 .read(&mut state_vector_ocl_result)
141 .enq()
142 .map_err(|e| Error::OpenCLError(format!("Failed to read state buffer: {}", e)))?;
143
144 Ok(state_vector_ocl_result
145 .iter()
146 .map(|f2| Complex::new(f2[0] as f64, f2[1] as f64))
147 .collect())
148}
149
150pub trait Operator: Send + Sync + Debug + DynClone + Display {
152 fn apply(
166 &self,
167 state: &State,
168 target_qubits: &[usize],
169 control_qubits: &[usize],
170 ) -> Result<State, Error>;
171
172 fn base_qubits(&self) -> usize;
178
179 fn to_compilable(&self) -> Option<&dyn Compilable> {
187 None
189 }
190}
191
192dyn_clone::clone_trait_object!(Operator);
193
194fn check_controls(index: usize, control_qubits: &[usize]) -> bool {
196 control_qubits
197 .iter()
198 .all(|&qubit| (index >> qubit) & 1 == 1)
199}
200
201fn validate_qubits(
215 state: &State,
216 target_qubits: &[usize],
217 control_qubits: &[usize],
218 expected_targets: usize,
219) -> Result<(), Error> {
220 if target_qubits.len() != expected_targets {
222 return Err(Error::InvalidNumberOfQubits(target_qubits.len()));
223 }
224
225 let num_qubits = state.num_qubits();
226
227 for &target_qubit in target_qubits {
229 if target_qubit >= num_qubits {
230 return Err(Error::InvalidQubitIndex(target_qubit, num_qubits));
231 }
232 }
233
234 for &control_qubit in control_qubits {
236 if control_qubit >= num_qubits {
237 return Err(Error::InvalidQubitIndex(control_qubit, num_qubits));
238 }
239
240 for &target_qubit in target_qubits {
241 if control_qubit == target_qubit {
242 return Err(Error::OverlappingControlAndTargetQubits(
243 control_qubit,
244 target_qubit,
245 ));
246 }
247 }
248 }
249
250 if expected_targets > 1 {
252 if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
253 let mut seen_targets: HashSet<usize> = HashSet::with_capacity(target_qubits.len());
255 for &target_qubit in target_qubits {
256 if !seen_targets.insert(target_qubit) {
257 return Err(Error::InvalidQubitIndex(target_qubit, num_qubits));
258 }
259 }
260 } else {
261 for i in 0..target_qubits.len() {
263 for j in i + 1..target_qubits.len() {
264 if target_qubits[i] == target_qubits[j] {
265 return Err(Error::InvalidQubitIndex(target_qubits[i], num_qubits));
266 }
267 }
268 }
269 }
270 }
271
272 Ok(())
273}
274
275#[derive(Debug, Clone, Copy)]
279pub struct Hadamard;
280
281impl Operator for Hadamard {
282 fn apply(
304 &self,
305 state: &State,
306 target_qubits: &[usize],
307 control_qubits: &[usize],
308 ) -> Result<State, Error> {
309 validate_qubits(state, target_qubits, control_qubits, 1)?;
311
312 let target_qubit: usize = target_qubits[0];
313 let num_qubits: usize = state.num_qubits();
314
315 let sqrt_2_inv: f64 = 1.0 / (2.0f64).sqrt();
317 let dim: usize = 1 << num_qubits;
318 #[allow(unused_assignments)]
319 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
320 let gpu_enabled: bool = cfg!(feature = "gpu");
321
322 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
323 #[cfg(feature = "gpu")]
324 {
325 let global_work_size = if num_qubits > 0 {
326 1 << (num_qubits - 1)
327 } else {
328 1
329 };
330 new_state_vec = execute_on_gpu(
331 state,
332 target_qubit,
333 control_qubits,
334 KernelType::Hadamard,
335 global_work_size,
336 GpuKernelArgs::None,
337 )?;
338 }
339 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
340 new_state_vec = state.state_vector.clone(); if control_qubits.is_empty() {
343 let updates: Vec<(usize, Complex<f64>)> = (0..(1 << (num_qubits - 1)))
345 .into_par_iter()
346 .flat_map(|k| {
347 let i0 = (k >> target_qubit << (target_qubit + 1))
348 | (k & ((1 << target_qubit) - 1));
349 let i1 = i0 | (1 << target_qubit);
350 let amp0 = state.state_vector[i0];
351 let amp1 = state.state_vector[i1];
352 vec![
353 (i0, sqrt_2_inv * (amp0 + amp1)),
354 (i1, sqrt_2_inv * (amp0 - amp1)),
355 ]
356 })
357 .collect();
358 for (idx, val) in updates {
359 new_state_vec[idx] = val;
360 }
361 } else {
362 let updates: Vec<(usize, Complex<f64>)> = (0..dim)
364 .into_par_iter()
365 .filter_map(|i| {
366 if (i >> target_qubit) & 1 == 0 {
367 let j = i | (1 << target_qubit); if check_controls(i, control_qubits) {
370 let amp_i = state.state_vector[i];
372 let amp_j = state.state_vector[j];
373 Some(vec![
374 (i, sqrt_2_inv * (amp_i + amp_j)),
375 (j, sqrt_2_inv * (amp_i - amp_j)),
376 ])
377 } else {
378 None }
380 } else {
381 None }
383 })
384 .flatten()
385 .collect();
386 for (idx, val) in updates {
387 new_state_vec[idx] = val;
388 }
389 }
390 } else {
391 new_state_vec = state.state_vector.clone(); if control_qubits.is_empty() {
394 for k in 0..(1 << (num_qubits - 1)) {
396 let i0 =
397 (k >> target_qubit << (target_qubit + 1)) | (k & ((1 << target_qubit) - 1));
398 let i1 = i0 | (1 << target_qubit);
399 let amp0 = state.state_vector[i0];
400 let amp1 = state.state_vector[i1];
401 new_state_vec[i0] = sqrt_2_inv * (amp0 + amp1);
402 new_state_vec[i1] = sqrt_2_inv * (amp0 - amp1);
403 }
404 } else {
405 for i in 0..dim {
407 if (i >> target_qubit) & 1 == 0 {
408 let j = i | (1 << target_qubit);
409 if check_controls(i, control_qubits) {
410 let amp_i = state.state_vector[i];
411 let amp_j = state.state_vector[j];
412 new_state_vec[i] = sqrt_2_inv * (amp_i + amp_j);
413 new_state_vec[j] = sqrt_2_inv * (amp_i - amp_j);
414 }
415 }
416 }
417 }
418 }
419
420 Ok(State {
421 state_vector: new_state_vec,
422 num_qubits,
423 })
424 }
425
426 fn base_qubits(&self) -> usize {
427 1 }
429
430 fn to_compilable(&self) -> Option<&dyn Compilable> {
431 Some(self)
432 }
433}
434
435impl Display for Hadamard {
436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 write!(f, "H")
438 }
439}
440
441#[derive(Debug, Clone, Copy, PartialEq)]
443pub enum Pauli {
444 X,
446 Y,
448 Z,
450}
451
452impl Operator for Pauli {
453 fn apply(
475 &self,
476 state: &State,
477 target_qubits: &[usize],
478 control_qubits: &[usize],
479 ) -> Result<State, Error> {
480 validate_qubits(state, target_qubits, control_qubits, 1)?;
482
483 let target_qubit: usize = target_qubits[0];
484 let num_qubits: usize = state.num_qubits();
485
486 let dim: usize = 1 << num_qubits;
488 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
489 let i_complex: Complex<f64> = Complex::new(0.0, 1.0);
490 let gpu_enabled: bool = cfg!(feature = "gpu");
491
492 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
493 #[cfg(feature = "gpu")]
494 {
495 let kernel_type = match self {
496 Pauli::X => KernelType::PauliX,
497 Pauli::Y => KernelType::PauliY,
498 Pauli::Z => KernelType::PauliZ,
499 };
500 let global_work_size = if num_qubits == 0 {
501 1
502 } else {
503 match self {
504 Pauli::Z => 1 << num_qubits, _ => 1 << (num_qubits - 1), }
507 };
508 new_state_vec = execute_on_gpu(
509 state,
510 target_qubit,
511 control_qubits,
512 kernel_type,
513 global_work_size,
514 GpuKernelArgs::None,
515 )?;
516 }
517 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
518 match self {
520 Pauli::X => {
521 let updates: Vec<(usize, Complex<f64>)> = (0..dim)
522 .into_par_iter()
523 .filter_map(|i| {
524 if check_controls(i, control_qubits) && ((i >> target_qubit) & 1 == 0) {
525 let j = i | (1 << target_qubit);
526 let amp_i = state.state_vector[i];
527 let amp_j = state.state_vector[j];
528 Some(vec![(i, amp_j), (j, amp_i)])
529 } else {
530 None
531 }
532 })
533 .flatten()
534 .collect();
535 for (idx, val) in updates {
536 new_state_vec[idx] = val;
537 }
538 }
539 Pauli::Y => {
540 let updates: Vec<(usize, Complex<f64>)> = (0..dim)
541 .into_par_iter()
542 .filter_map(|i| {
543 if check_controls(i, control_qubits) && ((i >> target_qubit) & 1 == 0) {
544 let j = i | (1 << target_qubit);
545 let amp_i = state.state_vector[i];
546 let amp_j = state.state_vector[j];
547 Some(vec![(i, -i_complex * amp_j), (j, i_complex * amp_i)])
548 } else {
549 None
550 }
551 })
552 .flatten()
553 .collect();
554 for (idx, val) in updates {
555 new_state_vec[idx] = val;
556 }
557 }
558 Pauli::Z => {
559 new_state_vec
560 .par_iter_mut()
561 .enumerate()
562 .for_each(|(i, current_amp_ref)| {
563 if check_controls(i, control_qubits) && ((i >> target_qubit) & 1 == 1) {
564 *current_amp_ref = -state.state_vector[i];
565 }
566 });
567 }
568 }
569 } else {
570 for i in 0..dim {
572 if check_controls(i, control_qubits) {
573 match self {
574 Pauli::X => {
575 if (i >> target_qubit) & 1 == 0 {
576 let j = i | (1 << target_qubit);
577 let amp_i = state.state_vector[i];
578 let amp_j = state.state_vector[j];
579 new_state_vec[i] = amp_j;
580 new_state_vec[j] = amp_i;
581 }
582 }
583 Pauli::Y => {
584 if (i >> target_qubit) & 1 == 0 {
585 let j = i | (1 << target_qubit);
586 let amp_i = state.state_vector[i];
587 let amp_j = state.state_vector[j];
588 new_state_vec[i] = -i_complex * amp_j;
589 new_state_vec[j] = i_complex * amp_i;
590 }
591 }
592 Pauli::Z => {
593 if (i >> target_qubit) & 1 == 1 {
594 new_state_vec[i] = -state.state_vector[i];
595 }
596 }
597 }
598 }
599 }
600 }
601
602 Ok(State {
603 state_vector: new_state_vec,
604 num_qubits: state.num_qubits(),
605 })
606 }
607
608 fn base_qubits(&self) -> usize {
609 1 }
611
612 fn to_compilable(&self) -> Option<&dyn Compilable> {
613 Some(self) }
615}
616
617impl std::fmt::Display for Pauli {
618 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
619 match self {
620 Pauli::X => write!(f, "X"),
621 Pauli::Y => write!(f, "Y"),
622 Pauli::Z => write!(f, "Z"),
623 }
624 }
625}
626
627impl Pauli {
628 pub fn to_pauli_string(&self, target_qubit: usize) -> PauliString {
633 let mut pauli_map = std::collections::HashMap::new();
634 pauli_map.insert(target_qubit, *self);
635 PauliString::with_ops(1.0.into(), pauli_map)
636 }
637}
638
639#[derive(Debug, Clone, Copy)]
643pub struct CNOT;
644
645impl Operator for CNOT {
646 fn apply(
668 &self,
669 state: &State,
670 target_qubits: &[usize],
671 control_qubits: &[usize],
672 ) -> Result<State, Error> {
673 validate_qubits(state, target_qubits, control_qubits, 1)?;
675
676 if control_qubits.len() != 1 {
678 return Err(Error::InvalidNumberOfQubits(control_qubits.len()));
679 }
680
681 let control_qubit: usize = control_qubits[0];
682
683 Pauli::X.apply(state, target_qubits, &[control_qubit])
685 }
686
687 fn base_qubits(&self) -> usize {
688 2 }
690
691 fn to_compilable(&self) -> Option<&dyn Compilable> {
692 Some(self)
693 }
694}
695
696impl std::fmt::Display for CNOT {
697 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
698 write!(f, "CNOT")
699 }
700}
701
702#[derive(Debug, Clone, Copy)]
706pub struct SWAP;
707
708impl Operator for SWAP {
709 fn apply(
732 &self,
733 state: &State,
734 target_qubits: &[usize],
735 control_qubits: &[usize],
736 ) -> Result<State, Error> {
737 validate_qubits(state, target_qubits, control_qubits, 2)?;
739
740 let target_qubit_1: usize = target_qubits[0];
741 let target_qubit_2: usize = target_qubits[1];
742 let num_qubits: usize = state.num_qubits();
743
744 let dim: usize = 1 << num_qubits;
746 #[allow(unused_assignments)] let mut new_state_vec = state.state_vector.clone(); let gpu_enabled: bool = cfg!(feature = "gpu");
749
750 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
751 #[cfg(feature = "gpu")]
752 {
753 let global_work_size = if num_qubits >= 2 {
757 1 << (num_qubits - 2)
758 } else {
759 1
760 }; new_state_vec = execute_on_gpu(
762 state,
763 target_qubit_1, control_qubits,
765 KernelType::Swap,
766 global_work_size,
767 GpuKernelArgs::SwapTarget {
768 q1: target_qubit_2 as i32,
769 }, )?;
771 }
772 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
773 let updates: Vec<(usize, Complex<f64>)> = (0..dim)
775 .into_par_iter()
776 .filter_map(|i| {
777 let target_bit_1 = (i >> target_qubit_1) & 1;
778 let target_bit_2 = (i >> target_qubit_2) & 1;
779
780 if target_bit_1 != target_bit_2 {
781 let j = i ^ (1 << target_qubit_1) ^ (1 << target_qubit_2);
782 if i < j && check_controls(i, control_qubits) {
783 let amp_i = state.state_vector[i];
784 let amp_j = state.state_vector[j];
785 Some(vec![(i, amp_j), (j, amp_i)])
786 } else {
787 None
788 }
789 } else {
790 None
791 }
792 })
793 .flatten()
794 .collect();
795 for (idx, val) in updates {
796 new_state_vec[idx] = val;
797 }
798 } else {
799 for i in 0..dim {
801 let target_bit_1 = (i >> target_qubit_1) & 1;
802 let target_bit_2 = (i >> target_qubit_2) & 1;
803
804 if target_bit_1 != target_bit_2 {
805 let j = i ^ (1 << target_qubit_1) ^ (1 << target_qubit_2);
806 if i < j && check_controls(i, control_qubits) {
807 let amp_i = state.state_vector[i];
808 let amp_j = state.state_vector[j];
809 new_state_vec[i] = amp_j;
810 new_state_vec[j] = amp_i;
811 }
812 }
813 }
814 }
815
816 Ok(State {
817 state_vector: new_state_vec,
818 num_qubits: state.num_qubits(),
819 })
820 }
821
822 fn base_qubits(&self) -> usize {
823 2 }
825
826 fn to_compilable(&self) -> Option<&dyn Compilable> {
827 Some(self)
828 }
829}
830
831impl std::fmt::Display for SWAP {
832 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
833 write!(f, "SWAP")
834 }
835}
836
837#[derive(Debug, Clone, Copy)]
852pub struct Matchgate {
853 pub(crate) theta: f64,
854 pub(crate) phi1: f64,
855 pub(crate) phi2: f64,
856}
857
858impl Matchgate {
859 pub fn new(theta: f64, phi1: f64, phi2: f64) -> Self {
867 Matchgate { theta, phi1, phi2 }
868 }
869}
870
871impl Operator for Matchgate {
872 fn apply(
894 &self,
895 state: &State,
896 target_qubit: &[usize],
897 control_qubits: &[usize],
898 ) -> Result<State, Error> {
899 validate_qubits(state, target_qubit, control_qubits, 1)?;
900
901 let q1 = target_qubit[0];
902 if q1 == state.num_qubits() - 1 {
904 return Err(Error::InvalidQubitIndex(q1, state.num_qubits()));
905 }
906
907 let q2 = q1 + 1; let num_qubits = state.num_qubits();
910 let mut new_state_vec = state.state_vector.clone();
911 let gpu_enabled: bool = cfg!(feature = "gpu");
912
913 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
914 #[cfg(feature = "gpu")]
915 {
916 let global_work_size = 1 << (num_qubits - 2);
917 let cos_theta_half = (self.theta / 2.0).cos() as f32;
918 let sin_theta_half = (self.theta / 2.0).sin() as f32;
919 let exp_i_phi1 = Complex::new(0.0, self.phi1).exp();
920 let exp_i_phi2 = Complex::new(0.0, self.phi2).exp();
921
922 new_state_vec = execute_on_gpu(
923 state,
924 q1,
925 control_qubits,
926 KernelType::Matchgate,
927 global_work_size,
928 GpuKernelArgs::Matchgate {
929 q1: q2 as i32,
930 cos_theta_half,
931 sin_theta_half,
932 exp_i_phi1: Float2::new(exp_i_phi1.re as f32, exp_i_phi1.im as f32),
933 exp_i_phi2: Float2::new(exp_i_phi2.re as f32, exp_i_phi2.im as f32),
934 },
935 )?;
936 }
937 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
938 let cos_theta_half = (self.theta / 2.0).cos();
940 let sin_theta_half = (self.theta / 2.0).sin();
941 let exp_i_phi1 = Complex::new(0.0, self.phi1).exp();
942 let exp_i_phi2 = Complex::new(0.0, self.phi2).exp();
943
944 let updates: Vec<(usize, Complex<f64>)> = (0..(1 << (num_qubits - 2)))
945 .into_par_iter()
946 .flat_map(|i| {
947 let k = ((i >> q1) << (q1 + 1)) | (i & ((1 << q1) - 1));
948 let l = ((k >> (q2 - 1)) << q2) | (k & ((1 << (q2 - 1)) - 1));
949
950 let i01 = l | (1 << q1);
951 let i10 = l | (1 << q2);
952 let i11 = l | (1 << q1) | (1 << q2);
953
954 let mut updates = Vec::new();
955
956 if check_controls(i01, control_qubits) {
957 let amp01 = state.state_vector[i01];
958 let amp10 = state.state_vector[i10];
959
960 let new_amp01 =
961 cos_theta_half * amp01 - exp_i_phi1 * sin_theta_half * amp10;
962 let new_amp10 =
963 sin_theta_half * amp01 + exp_i_phi1 * cos_theta_half * amp10;
964
965 updates.push((i01, new_amp01));
966 updates.push((i10, new_amp10));
967 }
968
969 if check_controls(i11, control_qubits) {
970 let new_amp11 = state.state_vector[i11] * exp_i_phi2;
971 updates.push((i11, new_amp11));
972 }
973 updates
974 })
975 .collect();
976
977 for (idx, val) in updates {
978 new_state_vec[idx] = val;
979 }
980 } else {
981 let cos_theta_half = (self.theta / 2.0).cos();
983 let sin_theta_half = (self.theta / 2.0).sin();
984 let exp_i_phi1 = Complex::new(0.0, self.phi1).exp();
985 let exp_i_phi2 = Complex::new(0.0, self.phi2).exp();
986
987 for i in 0..(1 << (num_qubits - 2)) {
988 let k = ((i >> q1) << (q1 + 1)) | (i & ((1 << q1) - 1));
989 let l = ((k >> (q2 - 1)) << q2) | (k & ((1 << (q2 - 1)) - 1));
990
991 let i01 = l | (1 << q1);
992 let i10 = l | (1 << q2);
993 let i11 = l | (1 << q1) | (1 << q2);
994
995 if check_controls(i01, control_qubits) {
996 let amp01 = state.state_vector[i01];
997 let amp10 = state.state_vector[i10];
998
999 new_state_vec[i01] =
1000 cos_theta_half * amp01 - exp_i_phi1 * sin_theta_half * amp10;
1001 new_state_vec[i10] =
1002 sin_theta_half * amp01 + exp_i_phi1 * cos_theta_half * amp10;
1003 }
1004 if check_controls(i11, control_qubits) {
1005 new_state_vec[i11] = state.state_vector[i11] * exp_i_phi2;
1006 }
1007 }
1008 }
1009
1010 Ok(State {
1011 state_vector: new_state_vec,
1012 num_qubits,
1013 })
1014 }
1015
1016 fn base_qubits(&self) -> usize {
1017 2
1018 }
1019}
1020
1021impl std::fmt::Display for Matchgate {
1022 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1023 write!(f, "Matchgate({:.3}, {:.3}, {:.3})", self.theta, self.phi1, self.phi2)
1024 }
1025}
1026
1027#[derive(Debug, Clone, Copy)]
1031pub struct Toffoli;
1032
1033impl Operator for Toffoli {
1034 fn apply(
1056 &self,
1057 state: &State,
1058 target_qubits: &[usize],
1059 control_qubits: &[usize],
1060 ) -> Result<State, Error> {
1061 validate_qubits(state, target_qubits, control_qubits, 1)?;
1063
1064 if control_qubits.len() != 2 {
1066 return Err(Error::InvalidNumberOfQubits(control_qubits.len()));
1067 }
1068
1069 if control_qubits[0] == control_qubits[1] {
1071 return Err(Error::InvalidNumberOfQubits(control_qubits.len()));
1072 }
1073
1074 Pauli::X.apply(state, target_qubits, control_qubits)
1075 }
1076
1077 fn base_qubits(&self) -> usize {
1078 3 }
1080
1081 fn to_compilable(&self) -> Option<&dyn Compilable> {
1082 Some(self)
1083 }
1084}
1085
1086impl std::fmt::Display for Toffoli {
1087 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1088 write!(f, "Toffoli")
1089 }
1090}
1091
1092#[derive(Debug, Clone, Copy)]
1096pub struct Identity;
1097
1098impl Operator for Identity {
1099 fn apply(
1113 &self,
1114 state: &State,
1115 target_qubits: &[usize],
1116 control_qubits: &[usize],
1117 ) -> Result<State, Error> {
1118 validate_qubits(state, target_qubits, control_qubits, 1)?;
1120
1121 Ok(state.clone())
1123 }
1124
1125 fn base_qubits(&self) -> usize {
1126 1 }
1128
1129 fn to_compilable(&self) -> Option<&dyn Compilable> {
1130 Some(self)
1131 }
1132}
1133
1134impl std::fmt::Display for Identity {
1135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1136 write!(f, "I")
1137 }
1138}
1139
1140#[derive(Debug, Clone, Copy)]
1144pub struct PhaseS;
1145
1146impl Operator for PhaseS {
1147 fn apply(
1161 &self,
1162 state: &State,
1163 target_qubits: &[usize],
1164 control_qubits: &[usize],
1165 ) -> Result<State, Error> {
1166 validate_qubits(state, target_qubits, control_qubits, 1)?;
1168
1169 let target_qubit: usize = target_qubits[0];
1170 let num_qubits: usize = state.num_qubits();
1171
1172 #[allow(unused_assignments)]
1174 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1175 let gpu_enabled: bool = cfg!(feature = "gpu");
1176
1177 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1178 #[cfg(feature = "gpu")]
1179 {
1180 let global_work_size = 1 << num_qubits;
1181 new_state_vec = execute_on_gpu(
1182 state,
1183 target_qubit,
1184 control_qubits,
1185 KernelType::PhaseSOrSdag,
1186 global_work_size,
1187 GpuKernelArgs::SOrSdag { sign: 1.0f32 },
1188 )?;
1189 }
1190 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1191 let phase_factor = Complex::new(0.0, 1.0); new_state_vec = state.state_vector.clone(); new_state_vec
1194 .par_iter_mut()
1195 .enumerate()
1196 .for_each(|(i, current_amp_ref)| {
1197 if ((i >> target_qubit) & 1 == 1) && check_controls(i, control_qubits) {
1198 *current_amp_ref = state.state_vector[i] * phase_factor;
1199 }
1200 });
1201 } else {
1202 let phase_factor = Complex::new(0.0, 1.0); new_state_vec = state.state_vector.clone(); for (i, current_amp_ref) in new_state_vec.iter_mut().enumerate() {
1205 let target_bit_is_one = (i >> target_qubit) & 1 == 1;
1206 if target_bit_is_one && check_controls(i, control_qubits) {
1207 *current_amp_ref = state.state_vector[i] * phase_factor;
1208 }
1209 }
1210 }
1211
1212 Ok(State {
1213 state_vector: new_state_vec,
1214 num_qubits,
1215 })
1216 }
1217
1218 fn base_qubits(&self) -> usize {
1219 1 }
1221
1222 fn to_compilable(&self) -> Option<&dyn Compilable> {
1223 Some(self)
1224 }
1225}
1226
1227impl std::fmt::Display for PhaseS {
1228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1229 write!(f, "S")
1230 }
1231}
1232
1233#[derive(Debug, Clone, Copy)]
1237pub struct PhaseT;
1238
1239impl Operator for PhaseT {
1240 fn apply(
1254 &self,
1255 state: &State,
1256 target_qubits: &[usize],
1257 control_qubits: &[usize],
1258 ) -> Result<State, Error> {
1259 validate_qubits(state, target_qubits, control_qubits, 1)?;
1261
1262 let target_qubit = target_qubits[0];
1263 let num_qubits = state.num_qubits();
1264
1265 #[allow(unused_assignments)]
1267 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1268 let gpu_enabled: bool = cfg!(feature = "gpu");
1269
1270 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1271 #[cfg(feature = "gpu")]
1272 {
1273 let global_work_size = 1 << num_qubits;
1274 let angle = PI / 4.0;
1275 new_state_vec = execute_on_gpu(
1276 state,
1277 target_qubit,
1278 control_qubits,
1279 KernelType::PhaseShift,
1280 global_work_size,
1281 GpuKernelArgs::PhaseShift {
1282 cos_angle: angle.cos() as f32,
1283 sin_angle: angle.sin() as f32,
1284 },
1285 )?;
1286 }
1287 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1288 let invsqrt2: f64 = 1.0 / (2.0f64).sqrt();
1289 let phase_factor = Complex::new(invsqrt2, invsqrt2); new_state_vec = state.state_vector.clone(); new_state_vec
1292 .par_iter_mut()
1293 .enumerate()
1294 .for_each(|(i, current_amp_ref)| {
1295 if ((i >> target_qubit) & 1 == 1) && check_controls(i, control_qubits) {
1296 *current_amp_ref = state.state_vector[i] * phase_factor;
1297 }
1298 });
1299 } else {
1300 let invsqrt2: f64 = 1.0 / (2.0f64).sqrt();
1301 let phase_factor = Complex::new(invsqrt2, invsqrt2); new_state_vec = state.state_vector.clone(); for (i, current_amp_ref) in new_state_vec.iter_mut().enumerate() {
1304 let target_bit_is_one = (i >> target_qubit) & 1 == 1;
1305 if target_bit_is_one && check_controls(i, control_qubits) {
1306 *current_amp_ref = state.state_vector[i] * phase_factor;
1307 }
1308 }
1309 }
1310
1311 Ok(State {
1312 state_vector: new_state_vec,
1313 num_qubits,
1314 })
1315 }
1316
1317 fn base_qubits(&self) -> usize {
1318 1 }
1320
1321 fn to_compilable(&self) -> Option<&dyn Compilable> {
1322 Some(self)
1323 }
1324}
1325
1326impl std::fmt::Display for PhaseT {
1327 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1328 write!(f, "T")
1329 }
1330}
1331
1332#[derive(Debug, Clone, Copy)]
1336pub struct PhaseSdag;
1337
1338impl Operator for PhaseSdag {
1339 fn apply(
1353 &self,
1354 state: &State,
1355 target_qubits: &[usize],
1356 control_qubits: &[usize],
1357 ) -> Result<State, Error> {
1358 validate_qubits(state, target_qubits, control_qubits, 1)?;
1360
1361 let target_qubit = target_qubits[0];
1362 let num_qubits = state.num_qubits();
1363
1364 #[allow(unused_assignments)]
1366 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1367 let gpu_enabled: bool = cfg!(feature = "gpu");
1368
1369 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1370 #[cfg(feature = "gpu")]
1371 {
1372 let global_work_size = 1 << num_qubits;
1373 new_state_vec = execute_on_gpu(
1374 state,
1375 target_qubit,
1376 control_qubits,
1377 KernelType::PhaseSOrSdag,
1378 global_work_size,
1379 GpuKernelArgs::SOrSdag { sign: -1.0f32 },
1380 )?;
1381 }
1382 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1383 let phase_factor = Complex::new(0.0, -1.0); new_state_vec = state.state_vector.clone(); new_state_vec
1386 .par_iter_mut()
1387 .enumerate()
1388 .for_each(|(i, current_amp_ref)| {
1389 if ((i >> target_qubit) & 1 == 1) && check_controls(i, control_qubits) {
1390 *current_amp_ref = state.state_vector[i] * phase_factor;
1391 }
1392 });
1393 } else {
1394 let phase_factor = Complex::new(0.0, -1.0); new_state_vec = state.state_vector.clone(); for (i, current_amp_ref) in new_state_vec.iter_mut().enumerate() {
1397 let target_bit_is_one = (i >> target_qubit) & 1 == 1;
1398 if target_bit_is_one && check_controls(i, control_qubits) {
1399 *current_amp_ref = state.state_vector[i] * phase_factor;
1400 }
1401 }
1402 }
1403
1404 Ok(State {
1405 state_vector: new_state_vec,
1406 num_qubits,
1407 })
1408 }
1409
1410 fn base_qubits(&self) -> usize {
1411 1 }
1413
1414 fn to_compilable(&self) -> Option<&dyn Compilable> {
1415 Some(self)
1416 }
1417}
1418
1419impl std::fmt::Display for PhaseSdag {
1420 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1421 write!(f, "S†")
1422 }
1423}
1424
1425#[derive(Debug, Clone, Copy)]
1429pub struct PhaseTdag;
1430
1431impl Operator for PhaseTdag {
1432 fn apply(
1446 &self,
1447 state: &State,
1448 target_qubits: &[usize],
1449 control_qubits: &[usize],
1450 ) -> Result<State, Error> {
1451 validate_qubits(state, target_qubits, control_qubits, 1)?;
1453
1454 let target_qubit = target_qubits[0];
1455 let num_qubits = state.num_qubits();
1456
1457 #[allow(unused_assignments)]
1459 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1460 let gpu_enabled: bool = cfg!(feature = "gpu");
1461
1462 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1463 #[cfg(feature = "gpu")]
1464 {
1465 let global_work_size = 1 << num_qubits;
1466 let angle = -PI / 4.0;
1467 new_state_vec = execute_on_gpu(
1468 state,
1469 target_qubit,
1470 control_qubits,
1471 KernelType::PhaseShift,
1472 global_work_size,
1473 GpuKernelArgs::PhaseShift {
1474 cos_angle: angle.cos() as f32,
1475 sin_angle: angle.sin() as f32,
1476 },
1477 )?;
1478 }
1479 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1480 let invsqrt2: f64 = 1.0 / (2.0f64).sqrt();
1481 let phase_factor = Complex::new(invsqrt2, -invsqrt2);
1482 new_state_vec = state.state_vector.clone(); new_state_vec
1484 .par_iter_mut()
1485 .enumerate()
1486 .for_each(|(i, current_amp_ref)| {
1487 if ((i >> target_qubit) & 1 == 1) && check_controls(i, control_qubits) {
1488 *current_amp_ref = state.state_vector[i] * phase_factor;
1489 }
1490 });
1491 } else {
1492 let invsqrt2: f64 = 1.0 / (2.0f64).sqrt();
1493 let phase_factor = Complex::new(invsqrt2, -invsqrt2);
1494 new_state_vec = state.state_vector.clone(); for (i, current_amp_ref) in new_state_vec.iter_mut().enumerate() {
1496 let target_bit_is_one = (i >> target_qubit) & 1 == 1;
1497 if target_bit_is_one && check_controls(i, control_qubits) {
1498 *current_amp_ref = state.state_vector[i] * phase_factor;
1499 }
1500 }
1501 }
1502
1503 Ok(State {
1504 state_vector: new_state_vec,
1505 num_qubits,
1506 })
1507 }
1508
1509 fn base_qubits(&self) -> usize {
1510 1 }
1512
1513 fn to_compilable(&self) -> Option<&dyn Compilable> {
1514 Some(self)
1515 }
1516}
1517
1518impl std::fmt::Display for PhaseTdag {
1519 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1520 write!(f, "T†")
1521 }
1522}
1523
1524#[derive(Debug, Clone, Copy)]
1528pub struct PhaseShift {
1529 pub(crate) angle: f64,
1530}
1531
1532impl PhaseShift {
1533 pub fn new(angle: f64) -> Self {
1539 PhaseShift { angle }
1540 }
1541}
1542
1543impl Operator for PhaseShift {
1544 fn apply(
1566 &self,
1567 state: &State,
1568 target_qubits: &[usize],
1569 control_qubits: &[usize],
1570 ) -> Result<State, Error> {
1571 validate_qubits(state, target_qubits, control_qubits, 1)?;
1573
1574 let target_qubit = target_qubits[0];
1575 let num_qubits = state.num_qubits();
1576
1577 #[allow(unused_assignments)]
1579 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1580 let gpu_enabled: bool = cfg!(feature = "gpu");
1581
1582 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1583 #[cfg(feature = "gpu")]
1584 {
1585 let global_work_size = 1 << num_qubits;
1586 new_state_vec = execute_on_gpu(
1587 state,
1588 target_qubit,
1589 control_qubits,
1590 KernelType::PhaseShift,
1591 global_work_size,
1592 GpuKernelArgs::PhaseShift {
1593 cos_angle: self.angle.cos() as f32,
1594 sin_angle: self.angle.sin() as f32,
1595 },
1596 )?;
1597 }
1598 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1599 let phase_factor = Complex::new(self.angle.cos(), self.angle.sin());
1600 new_state_vec = state.state_vector.clone(); new_state_vec
1602 .par_iter_mut()
1603 .enumerate()
1604 .for_each(|(i, current_amp_ref)| {
1605 if ((i >> target_qubit) & 1 == 1) && check_controls(i, control_qubits) {
1606 *current_amp_ref = state.state_vector[i] * phase_factor;
1607 }
1608 });
1609 } else {
1610 let phase_factor = Complex::new(self.angle.cos(), self.angle.sin());
1611 new_state_vec = state.state_vector.clone(); for (i, current_amp_ref) in new_state_vec.iter_mut().enumerate() {
1613 let target_bit_is_one = (i >> target_qubit) & 1 == 1;
1614 if target_bit_is_one && check_controls(i, control_qubits) {
1615 *current_amp_ref = state.state_vector[i] * phase_factor;
1616 }
1617 }
1618 }
1619
1620 Ok(State {
1621 state_vector: new_state_vec,
1622 num_qubits,
1623 })
1624 }
1625
1626 fn base_qubits(&self) -> usize {
1627 1 }
1629
1630 fn to_compilable(&self) -> Option<&dyn Compilable> {
1631 Some(self)
1632 }
1633}
1634
1635impl std::fmt::Display for PhaseShift {
1636 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1637 write!(f, "P({:.3})", self.angle)
1638 }
1639}
1640
1641#[derive(Debug, Clone, Copy)]
1645pub struct RotateX {
1646 pub(crate) angle: f64,
1647}
1648
1649impl RotateX {
1650 pub fn new(angle: f64) -> Self {
1656 RotateX { angle }
1657 }
1658}
1659
1660impl Operator for RotateX {
1661 fn apply(
1675 &self,
1676 state: &State,
1677 target_qubits: &[usize],
1678 control_qubits: &[usize],
1679 ) -> Result<State, Error> {
1680 validate_qubits(state, target_qubits, control_qubits, 1)?;
1682
1683 let target_qubit = target_qubits[0];
1684 let num_qubits = state.num_qubits();
1685
1686 #[allow(unused_assignments)]
1688 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1689 let gpu_enabled: bool = cfg!(feature = "gpu");
1690
1691 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1692 #[cfg(feature = "gpu")]
1693 {
1694 let half_angle = self.angle / 2.0;
1695 let global_work_size = if num_qubits > 0 {
1696 1 << (num_qubits - 1)
1697 } else {
1698 1
1699 };
1700 new_state_vec = execute_on_gpu(
1701 state,
1702 target_qubit,
1703 control_qubits,
1704 KernelType::RotateX,
1705 global_work_size,
1706 GpuKernelArgs::RotationGate {
1707 cos_half_angle: half_angle.cos() as f32,
1708 sin_half_angle: half_angle.sin() as f32,
1709 },
1710 )?;
1711 }
1712 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1713 let half_angle: f64 = self.angle / 2.0;
1715 let cos_half: f64 = half_angle.cos();
1716 let sin_half: f64 = half_angle.sin();
1717 let i_complex: Complex<f64> = Complex::new(0.0, 1.0);
1718 let dim: usize = 1 << num_qubits;
1719 new_state_vec = state.state_vector.clone(); let updates: Vec<(usize, Complex<f64>)> = (0..dim)
1722 .into_par_iter()
1723 .filter_map(|i| {
1724 if ((i >> target_qubit) & 1 == 0) && check_controls(i, control_qubits) {
1725 let j = i | (1 << target_qubit);
1726 let amp_i = state.state_vector[i];
1727 let amp_j = state.state_vector[j];
1728 Some(vec![
1729 (i, cos_half * amp_i - i_complex * sin_half * amp_j),
1730 (j, -i_complex * sin_half * amp_i + cos_half * amp_j),
1731 ])
1732 } else {
1733 None
1734 }
1735 })
1736 .flatten()
1737 .collect();
1738 for (idx, val) in updates {
1739 new_state_vec[idx] = val;
1740 }
1741 } else {
1742 let half_angle: f64 = self.angle / 2.0;
1744 let cos_half: f64 = half_angle.cos();
1745 let sin_half: f64 = half_angle.sin();
1746 let i_complex: Complex<f64> = Complex::new(0.0, 1.0);
1747 let dim: usize = 1 << num_qubits;
1748 new_state_vec = state.state_vector.clone(); for i in 0..dim {
1751 if (i >> target_qubit) & 1 == 0 {
1752 let j = i | (1 << target_qubit);
1753 if check_controls(i, control_qubits) {
1754 let amp_i = state.state_vector[i];
1755 let amp_j = state.state_vector[j];
1756 new_state_vec[i] = cos_half * amp_i - i_complex * sin_half * amp_j;
1757 new_state_vec[j] = -i_complex * sin_half * amp_i + cos_half * amp_j;
1758 }
1759 }
1760 }
1761 }
1762
1763 Ok(State {
1764 state_vector: new_state_vec,
1765 num_qubits: state.num_qubits(),
1766 })
1767 }
1768
1769 fn base_qubits(&self) -> usize {
1770 1 }
1772
1773 fn to_compilable(&self) -> Option<&dyn Compilable> {
1774 Some(self)
1775 }
1776}
1777
1778impl std::fmt::Display for RotateX {
1779 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1780 write!(f, "RX({:.3})", self.angle)
1781 }
1782}
1783
1784#[derive(Debug, Clone, Copy)]
1788pub struct RotateY {
1789 pub(crate) angle: f64,
1790}
1791
1792impl RotateY {
1793 pub fn new(angle: f64) -> Self {
1799 RotateY { angle }
1800 }
1801}
1802
1803impl Operator for RotateY {
1804 fn apply(
1818 &self,
1819 state: &State,
1820 target_qubits: &[usize],
1821 control_qubits: &[usize],
1822 ) -> Result<State, Error> {
1823 validate_qubits(state, target_qubits, control_qubits, 1)?;
1825
1826 let target_qubit = target_qubits[0];
1827 let num_qubits = state.num_qubits();
1828
1829 #[allow(unused_assignments)]
1831 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1832 let gpu_enabled: bool = cfg!(feature = "gpu");
1833
1834 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1835 #[cfg(feature = "gpu")]
1836 {
1837 let half_angle = self.angle / 2.0;
1838 let global_work_size = if num_qubits > 0 {
1839 1 << (num_qubits - 1)
1840 } else {
1841 1
1842 };
1843 new_state_vec = execute_on_gpu(
1844 state,
1845 target_qubit,
1846 control_qubits,
1847 KernelType::RotateY,
1848 global_work_size,
1849 GpuKernelArgs::RotationGate {
1850 cos_half_angle: half_angle.cos() as f32,
1851 sin_half_angle: half_angle.sin() as f32,
1852 },
1853 )?;
1854 }
1855 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1856 let half_angle: f64 = self.angle / 2.0;
1858 let cos_half: f64 = half_angle.cos();
1859 let sin_half: f64 = half_angle.sin();
1860 let dim: usize = 1 << num_qubits;
1861 new_state_vec = state.state_vector.clone(); let updates: Vec<(usize, Complex<f64>)> = (0..dim)
1864 .into_par_iter()
1865 .filter_map(|i| {
1866 if ((i >> target_qubit) & 1 == 0) && check_controls(i, control_qubits) {
1867 let j = i | (1 << target_qubit);
1868 let amp_i = state.state_vector[i];
1869 let amp_j = state.state_vector[j];
1870 Some(vec![
1871 (i, cos_half * amp_i - sin_half * amp_j),
1872 (j, sin_half * amp_i + cos_half * amp_j),
1873 ])
1874 } else {
1875 None
1876 }
1877 })
1878 .flatten()
1879 .collect();
1880 for (idx, val) in updates {
1881 new_state_vec[idx] = val;
1882 }
1883 } else {
1884 let half_angle: f64 = self.angle / 2.0;
1886 let cos_half: f64 = half_angle.cos();
1887 let sin_half: f64 = half_angle.sin();
1888 let dim: usize = 1 << num_qubits;
1889 new_state_vec = state.state_vector.clone(); for i in 0..dim {
1892 if (i >> target_qubit) & 1 == 0 {
1893 let j = i | (1 << target_qubit);
1894 if check_controls(i, control_qubits) {
1895 let amp_i = state.state_vector[i];
1896 let amp_j = state.state_vector[j];
1897 new_state_vec[i] = cos_half * amp_i - sin_half * amp_j;
1898 new_state_vec[j] = sin_half * amp_i + cos_half * amp_j;
1899 }
1900 }
1901 }
1902 }
1903
1904 Ok(State {
1905 state_vector: new_state_vec,
1906 num_qubits: state.num_qubits(),
1907 })
1908 }
1909
1910 fn base_qubits(&self) -> usize {
1911 1 }
1913
1914 fn to_compilable(&self) -> Option<&dyn Compilable> {
1915 Some(self)
1916 }
1917}
1918
1919impl std::fmt::Display for RotateY {
1920 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1921 write!(f, "RY({:.3})", self.angle)
1922 }
1923}
1924
1925#[derive(Debug, Clone, Copy)]
1929pub struct RotateZ {
1930 pub(crate) angle: f64,
1931}
1932
1933impl RotateZ {
1934 pub fn new(angle: f64) -> Self {
1940 RotateZ { angle }
1941 }
1942}
1943
1944impl Operator for RotateZ {
1945 fn apply(
1959 &self,
1960 state: &State,
1961 target_qubits: &[usize],
1962 control_qubits: &[usize],
1963 ) -> Result<State, Error> {
1964 validate_qubits(state, target_qubits, control_qubits, 1)?;
1966
1967 let target_qubit = target_qubits[0];
1968 let num_qubits = state.num_qubits();
1969
1970 #[allow(unused_assignments)]
1972 let mut new_state_vec: Vec<Complex<f64>> = state.state_vector.clone();
1973 let gpu_enabled: bool = cfg!(feature = "gpu");
1974
1975 if num_qubits >= OPENCL_THRESHOLD_NUM_QUBITS && gpu_enabled {
1976 #[cfg(feature = "gpu")]
1977 {
1978 let half_angle = self.angle / 2.0;
1979 let global_work_size = 1 << num_qubits; new_state_vec = execute_on_gpu(
1981 state,
1982 target_qubit,
1983 control_qubits,
1984 KernelType::RotateZ,
1985 global_work_size,
1986 GpuKernelArgs::RotationGate {
1987 cos_half_angle: half_angle.cos() as f32,
1988 sin_half_angle: half_angle.sin() as f32,
1989 },
1990 )?;
1991 }
1992 } else if num_qubits >= PARALLEL_THRESHOLD_NUM_QUBITS {
1993 let half_angle = self.angle / 2.0;
1995 let phase_0 = Complex::new(half_angle.cos(), -half_angle.sin());
1996 let phase_1 = Complex::new(half_angle.cos(), half_angle.sin());
1997 new_state_vec = state.state_vector.clone(); new_state_vec
2000 .par_iter_mut()
2001 .enumerate()
2002 .for_each(|(i, current_amp_ref)| {
2003 if check_controls(i, control_qubits) {
2004 let target_bit_is_one = (i >> target_qubit) & 1 == 1;
2005 if target_bit_is_one {
2006 *current_amp_ref = state.state_vector[i] * phase_1;
2007 } else {
2008 *current_amp_ref = state.state_vector[i] * phase_0;
2009 }
2010 }
2011 });
2012 } else {
2013 let half_angle = self.angle / 2.0;
2015 let phase_0 = Complex::new(half_angle.cos(), -half_angle.sin());
2016 let phase_1 = Complex::new(half_angle.cos(), half_angle.sin());
2017 new_state_vec = state.state_vector.clone(); for (i, current_amp_ref) in new_state_vec.iter_mut().enumerate() {
2020 if check_controls(i, control_qubits) {
2021 let target_bit_is_one = (i >> target_qubit) & 1 == 1;
2022 if target_bit_is_one {
2023 *current_amp_ref = state.state_vector[i] * phase_1;
2024 } else {
2025 *current_amp_ref = state.state_vector[i] * phase_0;
2026 }
2027 }
2028 }
2029 }
2030
2031 Ok(State {
2032 state_vector: new_state_vec,
2033 num_qubits: state.num_qubits(),
2034 })
2035 }
2036
2037 fn base_qubits(&self) -> usize {
2038 1 }
2040
2041 fn to_compilable(&self) -> Option<&dyn Compilable> {
2042 Some(self)
2043 }
2044}
2045
2046impl std::fmt::Display for RotateZ {
2047 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2048 write!(f, "RZ({:.3})", self.angle)
2049 }
2050}
2051
2052#[derive(Debug, Clone, Copy)]
2058pub struct Unitary2 {
2059 pub(crate) matrix: [[Complex<f64>; 2]; 2],
2061 pub(crate) is_ryphase: IsRyPhase
2063}
2064
2065#[derive(Debug, Clone, Copy, PartialEq)]
2067pub(crate) enum IsRyPhase {
2068 RYPhase(f64, f64), RYPhaseDagger(f64, f64), None
2076}
2077
2078impl Unitary2 {
2079 pub fn new(matrix: [[Complex<f64>; 2]; 2]) -> Result<Self, Error> {
2093 let tol: f64 = f64::EPSILON * 2.0; let a: Complex<f64> = matrix[0][0]; let b: Complex<f64> = matrix[0][1]; let c: Complex<f64> = matrix[1][0]; let d: Complex<f64> = matrix[1][1]; if ((a.norm_sqr() + b.norm_sqr()) - 1.0).abs() > tol {
2103 return Err(Error::NonUnitaryMatrix);
2104 }
2105 if ((c.norm_sqr() + d.norm_sqr()) - 1.0).abs() > tol {
2107 return Err(Error::NonUnitaryMatrix);
2108 }
2109
2110 if (a * c.conj() + b * d.conj()).norm_sqr() > tol * tol {
2113 return Err(Error::NonUnitaryMatrix);
2115 }
2116
2117 Ok(Unitary2 { matrix, is_ryphase: IsRyPhase::None })
2118 }
2119
2120 pub fn from_ry_phase(theta: f64, phi: f64) -> Self {
2141 let cos_half_theta = (theta / 2.0).cos();
2142 let sin_half_theta = (theta / 2.0).sin();
2143 let expi_phi = Complex::new(0.0, phi).exp();
2144
2145 let matrix = [
2147 [
2148 Complex::new(cos_half_theta, 0.0),
2149 -expi_phi * sin_half_theta,
2150 ],
2151 [Complex::new(sin_half_theta, 0.0), expi_phi * cos_half_theta],
2152 ];
2153
2154 Unitary2 { matrix, is_ryphase: IsRyPhase::RYPhase(theta, phi) }
2156 }
2157
2158 pub fn from_ry_phase_dagger(theta: f64, phi: f64) -> Self {
2174 let cos_half_theta = (theta / 2.0).cos();
2175 let sin_half_theta = (theta / 2.0).sin();
2176 let expi_neg_phi = Complex::new(0.0, -phi).exp();
2177
2178 let matrix = [
2180 [
2181 Complex::new(cos_half_theta, 0.0),
2182 Complex::new(sin_half_theta, 0.0),
2183 ],
2184 [
2185 -expi_neg_phi * sin_half_theta,
2186 expi_neg_phi * cos_half_theta,
2187 ],
2188 ];
2189
2190 Unitary2 { matrix, is_ryphase: IsRyPhase::RYPhaseDagger(theta, phi) }
2192 }
2193}
2194
2195impl Operator for Unitary2 {
2196 fn apply(
2210 &self,
2211 state: &State,
2212 target_qubits: &[usize],
2213 control_qubits: &[usize],
2214 ) -> Result<State, Error> {
2215 validate_qubits(state, target_qubits, control_qubits, 1)?;
2217
2218 let t: usize = target_qubits[0];
2219 let nq: usize = state.num_qubits();
2220
2221 let dim = 1 << nq;
2223 let mut new_state_vec = state.state_vector.clone();
2224
2225 if nq >= PARALLEL_THRESHOLD_NUM_QUBITS {
2226 let updates: Vec<(usize, Complex<f64>)> = (0..dim)
2228 .into_par_iter()
2229 .filter_map(|i| {
2230 if ((i >> t) & 1 == 0) && check_controls(i, control_qubits) {
2231 let j = i | (1 << t);
2232 let ai = state.state_vector[i];
2233 let aj = state.state_vector[j];
2234 Some(vec![
2235 (i, self.matrix[0][0] * ai + self.matrix[0][1] * aj),
2236 (j, self.matrix[1][0] * ai + self.matrix[1][1] * aj),
2237 ])
2238 } else {
2239 None
2240 }
2241 })
2242 .flatten()
2243 .collect();
2244 for (idx, val) in updates {
2245 new_state_vec[idx] = val;
2246 }
2247 } else {
2248 for i in 0..dim {
2250 if (i >> t) & 1 == 0 {
2251 let j = i | (1 << t);
2252 if check_controls(i, control_qubits) {
2253 let ai = state.state_vector[i];
2254 let aj = state.state_vector[j];
2255 new_state_vec[i] = self.matrix[0][0] * ai + self.matrix[0][1] * aj;
2256 new_state_vec[j] = self.matrix[1][0] * ai + self.matrix[1][1] * aj;
2257 }
2258 }
2259 }
2260 }
2261
2262 Ok(State {
2263 state_vector: new_state_vec,
2264 num_qubits: nq,
2265 })
2266 }
2267
2268 fn base_qubits(&self) -> usize {
2269 1
2270 }
2271
2272 fn to_compilable(&self) -> Option<&dyn Compilable> {
2273 Some(self)
2274 }
2275}
2276
2277impl std::fmt::Display for Unitary2 {
2278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2279 match self.is_ryphase {
2280 IsRyPhase::RYPhase(theta, phi) => write!(f, "RYP({:.3}, {:.3})", theta, phi),
2281 IsRyPhase::RYPhaseDagger(theta, phi) => write!(f, "RYP†({:.3}, {:.3})", theta, phi),
2282 IsRyPhase::None => write!(f, "Unitary2"),
2283 }
2284 }
2285}