diff --git a/crates/circuit/src/gate_matrix.rs b/crates/circuit/src/gate_matrix.rs index 2f085ea79c0a..074b1c2ac682 100644 --- a/crates/circuit/src/gate_matrix.rs +++ b/crates/circuit/src/gate_matrix.rs @@ -53,6 +53,43 @@ pub fn rz_gate(theta: f64) -> GateArray1Q { [[(-ilam2).exp(), C_ZERO], [C_ZERO, ilam2.exp()]] } +#[inline] +pub fn crx_gate(theta: f64) -> GateArray2Q { + let half_theta = theta / 2.; + let cos = c64(half_theta.cos(), 0.); + let isin = c64(0., half_theta.sin()); + [ + [C_ONE, C_ZERO, C_ZERO, C_ZERO], + [C_ZERO, cos, C_ZERO, -isin], + [C_ZERO, C_ZERO, C_ONE, C_ZERO], + [C_ZERO, -isin, C_ZERO, cos], + ] +} + +#[inline] +pub fn cry_gate(theta: f64) -> GateArray2Q { + let half_theta = theta / 2.; + let cos = c64(half_theta.cos(), 0.); + let sin = c64(half_theta.sin(), 0.); + [ + [C_ONE, C_ZERO, C_ZERO, C_ZERO], + [C_ZERO, cos, C_ZERO, -sin], + [C_ZERO, C_ZERO, C_ONE, C_ZERO], + [C_ZERO, sin, C_ZERO, cos], + ] +} + +#[inline] +pub fn crz_gate(theta: f64) -> GateArray2Q { + let i_half_theta = c64(0., theta / 2.); + [ + [C_ONE, C_ZERO, C_ZERO, C_ZERO], + [C_ZERO, (-i_half_theta).exp(), C_ZERO, C_ZERO], + [C_ZERO, C_ZERO, C_ONE, C_ZERO], + [C_ZERO, C_ZERO, C_ZERO, i_half_theta.exp()], + ] +} + pub static H_GATE: GateArray1Q = [ [c64(FRAC_1_SQRT_2, 0.), c64(FRAC_1_SQRT_2, 0.)], [c64(FRAC_1_SQRT_2, 0.), c64(-FRAC_1_SQRT_2, 0.)], diff --git a/crates/circuit/src/imports.rs b/crates/circuit/src/imports.rs index bf06685ba53b..530e635c94f1 100644 --- a/crates/circuit/src/imports.rs +++ b/crates/circuit/src/imports.rs @@ -151,11 +151,11 @@ static STDGATE_IMPORT_PATHS: [[&str; 2]; STANDARD_GATE_SIZE] = [ // U3Gate = 28 ["qiskit.circuit.library.standard_gates.u3", "U3Gate"], // CRXGate = 29 - ["placeholder", "placeholder"], + ["qiskit.circuit.library.standard_gates.rx", "CRXGate"], // CRYGate = 30 - ["placeholder", "placeholder"], + ["qiskit.circuit.library.standard_gates.ry", "CRYGate"], // CRZGate = 31 - ["placeholder", "placeholder"], + ["qiskit.circuit.library.standard_gates.rz", "CRZGate"], // RGate 32 ["qiskit.circuit.library.standard_gates.r", "RGate"], // CHGate = 33 diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index ff730744c80f..85192b63dbd7 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -235,8 +235,8 @@ pub enum StandardGate { static STANDARD_GATE_NUM_QUBITS: [u32; STANDARD_GATE_SIZE] = [ 1, 1, 1, 2, 2, 2, 3, 1, 1, 1, // 0-9 2, 2, 1, 0, 1, 1, 1, 1, 1, 1, // 10-19 - 1, 1, 1, 2, 2, 2, 1, 1, 1, 34, // 20-29 - 34, 34, 1, 2, 2, 2, 2, 2, 3, 2, // 30-39 + 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, // 20-29 + 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, // 30-39 2, 2, 34, 34, 34, 2, 34, 34, 34, 34, // 40-49 34, 34, 34, // 50-52 ]; @@ -245,8 +245,8 @@ static STANDARD_GATE_NUM_QUBITS: [u32; STANDARD_GATE_SIZE] = [ static STANDARD_GATE_NUM_PARAMS: [u32; STANDARD_GATE_SIZE] = [ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, // 0-9 0, 0, 0, 1, 0, 0, 1, 3, 0, 0, // 10-19 - 0, 0, 0, 0, 2, 2, 1, 2, 3, 34, // 20-29 - 34, 34, 2, 0, 1, 0, 0, 0, 0, 3, // 30-39 + 0, 0, 0, 0, 2, 2, 1, 2, 3, 1, // 20-29 + 1, 1, 2, 0, 1, 0, 0, 0, 0, 3, // 30-39 1, 3, 34, 34, 34, 0, 34, 34, 34, 34, // 40-49 34, 34, 34, // 50-52 ]; @@ -422,6 +422,18 @@ impl Operation for StandardGate { [Param::Float(theta)] => Some(aview2(&gate_matrix::rz_gate(*theta)).to_owned()), _ => None, }, + Self::CRXGate => match params { + [Param::Float(theta)] => Some(aview2(&gate_matrix::crx_gate(*theta)).to_owned()), + _ => None, + }, + Self::CRYGate => match params { + [Param::Float(theta)] => Some(aview2(&gate_matrix::cry_gate(*theta)).to_owned()), + _ => None, + }, + Self::CRZGate => match params { + [Param::Float(theta)] => Some(aview2(&gate_matrix::crz_gate(*theta)).to_owned()), + _ => None, + }, Self::ECRGate => match params { [] => Some(aview2(&gate_matrix::ECR_GATE).to_owned()), _ => None, @@ -510,7 +522,6 @@ impl Operation for StandardGate { } _ => None, }, - Self::CRXGate | Self::CRYGate | Self::CRZGate => todo!(), Self::RGate => match params { [Param::Float(theta), Param::Float(phi)] => { Some(aview2(&gate_matrix::r_gate(*theta, *phi)).to_owned()) @@ -673,6 +684,94 @@ impl Operation for StandardGate { .expect("Unexpected Qiskit python bug"), ) }), + Self::CRXGate => Python::with_gil(|py| -> Option { + let theta = ¶ms[0]; + Some( + CircuitData::from_standard_gates( + py, + 2, + [ + ( + Self::PhaseGate, + smallvec![Param::Float(PI / 2.)], + smallvec![Qubit(1)], + ), + (Self::CXGate, smallvec![], smallvec![Qubit(0), Qubit(1)]), + ( + Self::UGate, + smallvec![ + multiply_param(theta, -0.5, py), + Param::Float(0.0), + Param::Float(0.0) + ], + smallvec![Qubit(1)], + ), + (Self::CXGate, smallvec![], smallvec![Qubit(0), Qubit(1)]), + ( + Self::UGate, + smallvec![ + multiply_param(theta, 0.5, py), + Param::Float(-PI / 2.), + Param::Float(0.0) + ], + smallvec![Qubit(1)], + ), + ], + Param::Float(0.0), + ) + .expect("Unexpected Qiskit Python bug!"), + ) + }), + Self::CRYGate => Python::with_gil(|py| -> Option { + let theta = ¶ms[0]; + Some( + CircuitData::from_standard_gates( + py, + 2, + [ + ( + Self::RYGate, + smallvec![multiply_param(theta, 0.5, py)], + smallvec![Qubit(1)], + ), + (Self::CXGate, smallvec![], smallvec![Qubit(0), Qubit(1)]), + ( + Self::RYGate, + smallvec![multiply_param(theta, -0.5, py)], + smallvec![Qubit(1)], + ), + (Self::CXGate, smallvec![], smallvec![Qubit(0), Qubit(1)]), + ], + Param::Float(0.0), + ) + .expect("Unexpected Qiskit Python bug!"), + ) + }), + Self::CRZGate => Python::with_gil(|py| -> Option { + let theta = ¶ms[0]; + Some( + CircuitData::from_standard_gates( + py, + 2, + [ + ( + Self::RZGate, + smallvec![multiply_param(theta, 0.5, py)], + smallvec![Qubit(1)], + ), + (Self::CXGate, smallvec![], smallvec![Qubit(0), Qubit(1)]), + ( + Self::RZGate, + smallvec![multiply_param(theta, -0.5, py)], + smallvec![Qubit(1)], + ), + (Self::CXGate, smallvec![], smallvec![Qubit(0), Qubit(1)]), + ], + Param::Float(0.0), + ) + .expect("Unexpected Qiskit Python bug!"), + ) + }), Self::ECRGate => todo!("Add when we have RZX"), Self::SwapGate => Python::with_gil(|py| -> Option { Some( @@ -962,7 +1061,6 @@ impl Operation for StandardGate { .expect("Unexpected Qiskit python bug"), ) }), - Self::CRXGate | Self::CRYGate | Self::CRZGate => todo!(), Self::RGate => Python::with_gil(|py| -> Option { let theta_expr = clone_param(¶ms[0], py); let phi_expr1 = add_param(¶ms[1], -PI / 2., py); diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index 5579f9d3707d..cb851a740d28 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -199,6 +199,8 @@ class CRXGate(ControlledGate): \end{pmatrix} """ + _standard_gate = StandardGate.CRXGate + def __init__( self, theta: ParameterValueType, diff --git a/qiskit/circuit/library/standard_gates/ry.py b/qiskit/circuit/library/standard_gates/ry.py index e27398cc2960..b60b34ffde6f 100644 --- a/qiskit/circuit/library/standard_gates/ry.py +++ b/qiskit/circuit/library/standard_gates/ry.py @@ -198,6 +198,8 @@ class CRYGate(ControlledGate): \end{pmatrix} """ + _standard_gate = StandardGate.CRYGate + def __init__( self, theta: ParameterValueType, diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index e8ee0f976036..78cf20efa5c6 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -216,6 +216,8 @@ class CRZGate(ControlledGate): phase difference. """ + _standard_gate = StandardGate.CRZGate + def __init__( self, theta: ParameterValueType, diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 485591a8a3bb..7b8fe6e031f1 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -4774,6 +4774,12 @@ def crx( """ from .library.standard_gates.rx import CRXGate + # if the control state is |1> use the fast Rust version of the gate + if ctrl_state is None or ctrl_state in ["1", 1]: + return self._append_standard_gate( + StandardGate.CRXGate, [theta], [control_qubit, target_qubit], None, label=label + ) + return self.append( CRXGate(theta, label=label, ctrl_state=ctrl_state), [control_qubit, target_qubit], @@ -4843,6 +4849,12 @@ def cry( """ from .library.standard_gates.ry import CRYGate + # if the control state is |1> use the fast Rust version of the gate + if ctrl_state is None or ctrl_state in ["1", 1]: + return self._append_standard_gate( + StandardGate.CRYGate, [theta], [control_qubit, target_qubit], None, label=label + ) + return self.append( CRYGate(theta, label=label, ctrl_state=ctrl_state), [control_qubit, target_qubit], @@ -4909,6 +4921,12 @@ def crz( """ from .library.standard_gates.rz import CRZGate + # if the control state is |1> use the fast Rust version of the gate + if ctrl_state is None or ctrl_state in ["1", 1]: + return self._append_standard_gate( + StandardGate.CRZGate, [theta], [control_qubit, target_qubit], None, label=label + ) + return self.append( CRZGate(theta, label=label, ctrl_state=ctrl_state), [control_qubit, target_qubit],