Skip to content

Commit

Permalink
Implement RGate in Rust (Qiskit#12662)
Browse files Browse the repository at this point in the history
* Implement RGate in Rust

* Update crates/circuit/src/operations.rs

Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>

* Fix error in decomposition of RGate

There is an error in the expression for decomposition of the R gate
in the port to Rust.

This fixes the error and re-enables the skipped test that failed because
of the incorrect expression.

* Factor cloning the Param enum in Rust

To clone the enum, each variant must be handled separately.  This is currently used once,
but can be used each time a `Param` is cloned. In case more work needs to be done within
match arms, one might choose not to use this function, but rather clone in each of these
arms.

* Run cargo fmt

* Implement and use addition for enum Param

This handles `Float` and `ParameterExpression` variants uniformly.

---------

Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>
  • Loading branch information
2 people authored and Procatv committed Aug 1, 2024
1 parent 2d2ed5c commit 23e0385
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 9 deletions.
13 changes: 13 additions & 0 deletions crates/circuit/src/gate_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ const fn c64(re: f64, im: f64) -> Complex64 {
pub static ONE_QUBIT_IDENTITY: [[Complex64; 2]; 2] =
[[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(1., 0.)]];

#[inline]
pub fn r_gate(theta: f64, phi: f64) -> [[Complex64; 2]; 2] {
let half_theta = theta / 2.;
let cost = c64(half_theta.cos(), 0.);
let sint = half_theta.sin();
let cosphi = phi.cos();
let sinphi = phi.sin();
[
[cost, c64(-sint * sinphi, -sint * cosphi)],
[c64(sint * sinphi, -sint * cosphi), cost],
]
}

#[inline]
pub fn rx_gate(theta: f64) -> [[Complex64; 2]; 2] {
let half_theta = theta / 2.;
Expand Down
2 changes: 1 addition & 1 deletion crates/circuit/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ static STDGATE_IMPORT_PATHS: [[&str; 2]; STANDARD_GATE_SIZE] = [
// CRZGate = 31
["placeholder", "placeholder"],
// RGate 32
["placeholder", "placeholder"],
["qiskit.circuit.library.standard_gates.r", "RGate"],
// CHGate = 33
["qiskit.circuit.library.standard_gates.h", "CHGate"],
// CPhaseGate = 34
Expand Down
52 changes: 47 additions & 5 deletions crates/circuit/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ 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, 34, 2, 2, 2, 2, 2, 3, 2, // 30-39
34, 34, 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 @@ -249,7 +249,7 @@ 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, 34, 0, 1, 0, 0, 0, 0, 3, // 30-39
34, 34, 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 @@ -514,7 +514,12 @@ impl Operation for StandardGate {
_ => None,
},
Self::CRXGate | Self::CRYGate | Self::CRZGate => todo!(),
Self::RGate => todo!(),
Self::RGate => match params {
[Param::Float(theta), Param::Float(phi)] => {
Some(aview2(&gate_matrix::r_gate(*theta, *phi)).to_owned())
}
_ => None,
},
Self::CHGate => todo!(),
Self::CPhaseGate => todo!(),
Self::CSGate => todo!(),
Expand Down Expand Up @@ -957,7 +962,21 @@ impl Operation for StandardGate {
)
}),
Self::CRXGate | Self::CRYGate | Self::CRZGate => todo!(),
Self::RGate => todo!(),
Self::RGate => Python::with_gil(|py| -> Option<CircuitData> {
let theta_expr = clone_param(&params[0], py);
let phi_expr1 = add_param(&params[1], -PI2, py);
let phi_expr2 = multiply_param(&phi_expr1, -1.0, py);
let defparams = smallvec![theta_expr, phi_expr1, phi_expr2];
Some(
CircuitData::from_standard_gates(
py,
1,
[(Self::UGate, defparams, smallvec![Qubit(0)])],
FLOAT_ZERO,
)
.expect("Unexpected Qiskit python bug"),
)
}),
Self::CHGate => todo!(),
Self::CPhaseGate => todo!(),
Self::CSGate => todo!(),
Expand Down Expand Up @@ -997,14 +1016,37 @@ impl Operation for StandardGate {

const FLOAT_ZERO: Param = Param::Float(0.0);

// Return explictly requested copy of `param`, handling
// each variant separately.
fn clone_param(param: &Param, py: Python) -> Param {
match param {
Param::Float(theta) => Param::Float(*theta),
Param::ParameterExpression(theta) => Param::ParameterExpression(theta.clone_ref(py)),
Param::Obj(_) => unreachable!(),
}
}

fn multiply_param(param: &Param, mult: f64, py: Python) -> Param {
match param {
Param::Float(theta) => Param::Float(*theta * mult),
Param::ParameterExpression(theta) => Param::ParameterExpression(
theta
.clone_ref(py)
.call_method1(py, intern!(py, "__rmul__"), (mult,))
.expect("Parameter expression for global phase failed"),
.expect("Multiplication of Parameter expression by float failed."),
),
Param::Obj(_) => unreachable!(),
}
}

fn add_param(param: &Param, summand: f64, py: Python) -> Param {
match param {
Param::Float(theta) => Param::Float(*theta + summand),
Param::ParameterExpression(theta) => Param::ParameterExpression(
theta
.clone_ref(py)
.call_method1(py, intern!(py, "__add__"), (summand,))
.expect("Sum of Parameter expression and float failed."),
),
Param::Obj(_) => unreachable!(),
}
Expand Down
3 changes: 3 additions & 0 deletions qiskit/circuit/library/standard_gates/r.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.parameterexpression import ParameterValueType
from qiskit._accelerate.circuit import StandardGate


class RGate(Gate):
Expand Down Expand Up @@ -49,6 +50,8 @@ class RGate(Gate):
\end{pmatrix}
"""

_standard_gate = StandardGate.RGate

def __init__(
self,
theta: ParameterValueType,
Expand Down
4 changes: 1 addition & 3 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4649,9 +4649,7 @@ def r(
Returns:
A handle to the instructions created.
"""
from .library.standard_gates.r import RGate

return self.append(RGate(theta, phi), [qubit], [], copy=False)
return self._append_standard_gate(StandardGate.RGate, [theta, phi], qargs=[qubit])

def rv(
self,
Expand Down

0 comments on commit 23e0385

Please sign in to comment.