Skip to content

Commit

Permalink
Add Rust representation for XXMinusYYGate and XXPlusYYGate (#12606)
Browse files Browse the repository at this point in the history
* Add XXMinusYYGate and XXPlusYYGate, implement parameter multiplication function (naive approach).

Co-authored by: Julien Gacon [email protected]

* * Format code

* Use multiply_param in RZGate

* Fix signs and indices
  • Loading branch information
ElePT authored Jun 21, 2024
1 parent 22c145a commit 87aa89c
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 39 deletions.
46 changes: 46 additions & 0 deletions crates/circuit/src/gate_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,13 +212,15 @@ pub static ISWAP_GATE: [[Complex64; 4]; 4] = [
];

pub static S_GATE: [[Complex64; 2]; 2] = [[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(0., 1.)]];

pub static SDG_GATE: [[Complex64; 2]; 2] =
[[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(0., -1.)]];

pub static T_GATE: [[Complex64; 2]; 2] = [
[c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(FRAC_1_SQRT_2, FRAC_1_SQRT_2)],
];

pub static TDG_GATE: [[Complex64; 2]; 2] = [
[c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(FRAC_1_SQRT_2, -FRAC_1_SQRT_2)],
Expand Down Expand Up @@ -246,3 +248,47 @@ pub fn u_gate(theta: f64, phi: f64, lam: f64) -> [[Complex64; 2]; 2] {
[c64(0., phi).exp() * sin, c64(0., phi + lam).exp() * cos],
]
}

#[inline]
pub fn xx_minus_yy_gate(theta: f64, beta: f64) -> [[Complex64; 4]; 4] {
let cos = (theta / 2.).cos();
let sin = (theta / 2.).sin();
[
[
c64(cos, 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., -sin) * c64(0., -beta).exp(),
],
[c64(0., 0.), c64(1., 0.), c64(0., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 0.), c64(1., 0.), c64(0., 0.)],
[
c64(0., -sin) * c64(0., beta).exp(),
c64(0., 0.),
c64(0., 0.),
c64(cos, 0.),
],
]
}

#[inline]
pub fn xx_plus_yy_gate(theta: f64, beta: f64) -> [[Complex64; 4]; 4] {
let cos = (theta / 2.).cos();
let sin = (theta / 2.).sin();
[
[c64(1., 0.), c64(0., 0.), c64(0., 0.), c64(0., 0.)],
[
c64(0., 0.),
c64(cos, 0.),
c64(0., -sin) * c64(0., -beta).exp(),
c64(0., 0.),
],
[
c64(0., 0.),
c64(0., -sin) * c64(0., beta).exp(),
c64(cos, 0.),
c64(0., 0.),
],
[c64(0., 0.), c64(0., 0.), c64(0., 0.), c64(1., 0.)],
]
}
14 changes: 12 additions & 2 deletions crates/circuit/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,23 @@ static STDGATE_IMPORT_PATHS: [[&str; 2]; STANDARD_GATE_SIZE] = [
// SdgGate = 19
["qiskit.circuit.library.standard_gates.s", "SdgGate"],
// TGate = 20
["qiskit.circuit.library.standard_gates.s", "TGate"],
["qiskit.circuit.library.standard_gates.t", "TGate"],
// TdgGate = 21
["qiskit.circuit.library.standard_gates.s", "TdgGate"],
["qiskit.circuit.library.standard_gates.t", "TdgGate"],
// SXdgGate = 22
["qiskit.circuit.library.standard_gates.sx", "SXdgGate"],
// iSWAPGate = 23
["qiskit.circuit.library.standard_gates.iswap", "iSwapGate"],
//XXMinusYYGate = 24
[
"qiskit.circuit.library.standard_gates.xx_minus_yy",
"XXMinusYYGate",
],
//XXPlusYYGate = 25
[
"qiskit.circuit.library.standard_gates.xx_plus_yy",
"XXPlusYYGate",
],
];

/// A mapping from the enum variant in crate::operations::StandardGate to the python object for the
Expand Down
167 changes: 130 additions & 37 deletions crates/circuit/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,16 @@ pub enum StandardGate {
TdgGate = 21,
SXdgGate = 22,
ISwapGate = 23,
XXMinusYYGate = 24,
XXPlusYYGate = 25,
}

static STANDARD_GATE_NUM_QUBITS: [u32; STANDARD_GATE_SIZE] = [
1, 1, 1, 2, 2, 2, 3, 1, 1, 1, 2, 2, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
1, 1, 1, 2, 2, 2, 3, 1, 1, 1, 2, 2, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
];

static STANDARD_GATE_NUM_PARAMS: [u32; STANDARD_GATE_SIZE] = [
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 2, 2,
];

static STANDARD_GATE_NAME: [&str; STANDARD_GATE_SIZE] = [
Expand Down Expand Up @@ -238,6 +240,8 @@ static STANDARD_GATE_NAME: [&str; STANDARD_GATE_SIZE] = [
"tdg",
"sxdg",
"iswap",
"xx_minus_yy",
"xx_plus_yy",
];

#[pymethods]
Expand Down Expand Up @@ -287,7 +291,7 @@ impl StandardGate {
// Remove this when std::mem::variant_count() is stabilized (see
// https://github.com/rust-lang/rust/issues/73662 )

pub const STANDARD_GATE_SIZE: usize = 24;
pub const STANDARD_GATE_SIZE: usize = 26;

impl Operation for StandardGate {
fn name(&self) -> &str {
Expand Down Expand Up @@ -416,6 +420,18 @@ impl Operation for StandardGate {
[] => Some(aview2(&gate_matrix::ISWAP_GATE).to_owned()),
_ => None,
},
Self::XXMinusYYGate => match params {
[Param::Float(theta), Param::Float(beta)] => {
Some(aview2(&gate_matrix::xx_minus_yy_gate(*theta, *beta)).to_owned())
}
_ => None,
},
Self::XXPlusYYGate => match params {
[Param::Float(theta), Param::Float(beta)] => {
Some(aview2(&gate_matrix::xx_plus_yy_gate(*theta, *beta)).to_owned())
}
_ => None,
},
}
}

Expand Down Expand Up @@ -502,6 +518,7 @@ impl Operation for StandardGate {
}),
Self::CXGate => None,
Self::CCXGate => Python::with_gil(|py| -> Option<CircuitData> {
let q0 = smallvec![Qubit(0)];
let q1 = smallvec![Qubit(1)];
let q2 = smallvec![Qubit(2)];
let q0_1 = smallvec![Qubit(0), Qubit(1)];
Expand All @@ -524,7 +541,7 @@ impl Operation for StandardGate {
(Self::TGate, smallvec![], q2.clone()),
(Self::HGate, smallvec![], q2),
(Self::CXGate, smallvec![], q0_1.clone()),
(Self::TGate, smallvec![], smallvec![Qubit(0)]),
(Self::TGate, smallvec![], q0),
(Self::TdgGate, smallvec![], q1),
(Self::CXGate, smallvec![], q0_1),
],
Expand All @@ -536,39 +553,20 @@ impl Operation for StandardGate {
Self::RXGate => todo!("Add when we have R"),
Self::RYGate => todo!("Add when we have R"),
Self::RZGate => Python::with_gil(|py| -> Option<CircuitData> {
match &params[0] {
Param::Float(theta) => Some(
CircuitData::from_standard_gates(
py,
1,
[(
Self::PhaseGate,
smallvec![Param::Float(*theta)],
smallvec![Qubit(0)],
)],
Param::Float(-0.5 * theta),
)
.expect("Unexpected Qiskit python bug"),
),
Param::ParameterExpression(theta) => Some(
CircuitData::from_standard_gates(
py,
1,
[(
Self::PhaseGate,
smallvec![Param::ParameterExpression(theta.clone_ref(py))],
smallvec![Qubit(0)],
)],
Param::ParameterExpression(
theta
.call_method1(py, intern!(py, "__rmul__"), (-0.5,))
.expect("Parameter expression for global phase failed"),
),
)
.expect("Unexpected Qiskit python bug"),
),
Param::Obj(_) => unreachable!(),
}
let theta = &params[0];
Some(
CircuitData::from_standard_gates(
py,
1,
[(
Self::PhaseGate,
smallvec![theta.clone()],
smallvec![Qubit(0)],
)],
multiply_param(theta, -0.5, py),
)
.expect("Unexpected Qiskit python bug"),
)
}),
Self::ECRGate => todo!("Add when we have RZX"),
Self::SwapGate => Python::with_gil(|py| -> Option<CircuitData> {
Expand Down Expand Up @@ -732,6 +730,88 @@ impl Operation for StandardGate {
.expect("Unexpected Qiskit python bug"),
)
}),
Self::XXMinusYYGate => Python::with_gil(|py| -> Option<CircuitData> {
let q0 = smallvec![Qubit(0)];
let q1 = smallvec![Qubit(1)];
let q0_1 = smallvec![Qubit(0), Qubit(1)];
let theta = &params[0];
let beta = &params[1];
Some(
CircuitData::from_standard_gates(
py,
2,
[
(
Self::RZGate,
smallvec![multiply_param(beta, -1.0, py)],
q1.clone(),
),
(Self::RZGate, smallvec![Param::Float(-PI2)], q0.clone()),
(Self::SXGate, smallvec![], q0.clone()),
(Self::RZGate, smallvec![Param::Float(PI2)], q0.clone()),
(Self::SGate, smallvec![], q1.clone()),
(Self::CXGate, smallvec![], q0_1.clone()),
(
Self::RYGate,
smallvec![multiply_param(theta, 0.5, py)],
q0.clone(),
),
(
Self::RYGate,
smallvec![multiply_param(theta, -0.5, py)],
q1.clone(),
),
(Self::CXGate, smallvec![], q0_1),
(Self::SdgGate, smallvec![], q1.clone()),
(Self::RZGate, smallvec![Param::Float(-PI2)], q0.clone()),
(Self::SXdgGate, smallvec![], q0.clone()),
(Self::RZGate, smallvec![Param::Float(PI2)], q0),
(Self::RZGate, smallvec![beta.clone()], q1),
],
FLOAT_ZERO,
)
.expect("Unexpected Qiskit python bug"),
)
}),
Self::XXPlusYYGate => Python::with_gil(|py| -> Option<CircuitData> {
let q0 = smallvec![Qubit(0)];
let q1 = smallvec![Qubit(1)];
let q1_0 = smallvec![Qubit(1), Qubit(0)];
let theta = &params[0];
let beta = &params[1];
Some(
CircuitData::from_standard_gates(
py,
2,
[
(Self::RZGate, smallvec![beta.clone()], q0.clone()),
(Self::RZGate, smallvec![Param::Float(-PI2)], q1.clone()),
(Self::SXGate, smallvec![], q1.clone()),
(Self::RZGate, smallvec![Param::Float(PI2)], q1.clone()),
(Self::SGate, smallvec![], q0.clone()),
(Self::CXGate, smallvec![], q1_0.clone()),
(
Self::RYGate,
smallvec![multiply_param(theta, -0.5, py)],
q1.clone(),
),
(
Self::RYGate,
smallvec![multiply_param(theta, -0.5, py)],
q0.clone(),
),
(Self::CXGate, smallvec![], q1_0),
(Self::SdgGate, smallvec![], q0.clone()),
(Self::RZGate, smallvec![Param::Float(-PI2)], q1.clone()),
(Self::SXdgGate, smallvec![], q1.clone()),
(Self::RZGate, smallvec![Param::Float(PI2)], q1),
(Self::RZGate, smallvec![multiply_param(beta, -1.0, py)], q0),
],
FLOAT_ZERO,
)
.expect("Unexpected Qiskit python bug"),
)
}),
}
}

Expand All @@ -742,6 +822,19 @@ impl Operation for StandardGate {

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

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"),
),
Param::Obj(_) => unreachable!(),
}
}

/// This class is used to wrap a Python side Instruction that is not in the standard library
#[derive(Clone, Debug)]
#[pyclass(freelist = 20, module = "qiskit._accelerate.circuit")]
Expand Down
3 changes: 3 additions & 0 deletions qiskit/circuit/library/standard_gates/xx_minus_yy.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from qiskit.circuit.parameterexpression import ParameterValueType
from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit._accelerate.circuit import StandardGate


class XXMinusYYGate(Gate):
Expand Down Expand Up @@ -91,6 +92,8 @@ class XXMinusYYGate(Gate):
\end{pmatrix}
"""

_standard_gate = StandardGate.XXMinusYYGate

def __init__(
self,
theta: ParameterValueType,
Expand Down
3 changes: 3 additions & 0 deletions qiskit/circuit/library/standard_gates/xx_plus_yy.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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 XXPlusYYGate(Gate):
Expand Down Expand Up @@ -87,6 +88,8 @@ class XXPlusYYGate(Gate):
\end{pmatrix}
"""

_standard_gate = StandardGate.XXPlusYYGate

def __init__(
self,
theta: ParameterValueType,
Expand Down

0 comments on commit 87aa89c

Please sign in to comment.