Skip to content

Commit

Permalink
Port CRX/Y/Z gates to Rust (#12648)
Browse files Browse the repository at this point in the history
* v0 of CR-Pauli gates

* fix inevitable matrix typos

* update multiply_param

and prepare for U1/2/3 PR

* fix num params/qubits

* cct methods to append rust gates

---------

Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>
  • Loading branch information
Cryoris and ElePT authored Jun 28, 2024
1 parent 3adcd5d commit 9b0a584
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 9 deletions.
37 changes: 37 additions & 0 deletions crates/circuit/src/gate_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.)],
Expand Down
6 changes: 3 additions & 3 deletions crates/circuit/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
110 changes: 104 additions & 6 deletions crates/circuit/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
];
Expand All @@ -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
];
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -673,6 +684,94 @@ impl Operation for StandardGate {
.expect("Unexpected Qiskit python bug"),
)
}),
Self::CRXGate => Python::with_gil(|py| -> Option<CircuitData> {
let theta = &params[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<CircuitData> {
let theta = &params[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<CircuitData> {
let theta = &params[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<CircuitData> {
Some(
Expand Down Expand Up @@ -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<CircuitData> {
let theta_expr = clone_param(&params[0], py);
let phi_expr1 = add_param(&params[1], -PI / 2., py);
Expand Down
2 changes: 2 additions & 0 deletions qiskit/circuit/library/standard_gates/rx.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ class CRXGate(ControlledGate):
\end{pmatrix}
"""

_standard_gate = StandardGate.CRXGate

def __init__(
self,
theta: ParameterValueType,
Expand Down
2 changes: 2 additions & 0 deletions qiskit/circuit/library/standard_gates/ry.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ class CRYGate(ControlledGate):
\end{pmatrix}
"""

_standard_gate = StandardGate.CRYGate

def __init__(
self,
theta: ParameterValueType,
Expand Down
2 changes: 2 additions & 0 deletions qiskit/circuit/library/standard_gates/rz.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ class CRZGate(ControlledGate):
phase difference.
"""

_standard_gate = StandardGate.CRZGate

def __init__(
self,
theta: ParameterValueType,
Expand Down
18 changes: 18 additions & 0 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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],
Expand Down

0 comments on commit 9b0a584

Please sign in to comment.