Skip to content

Commit

Permalink
Merge branch 'main' into oxidize-basis-translator
Browse files Browse the repository at this point in the history
  • Loading branch information
raynelfss authored Oct 9, 2024
2 parents 71f2e1d + 90e92a4 commit 82d22f1
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 1 deletion.
198 changes: 197 additions & 1 deletion crates/circuit/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{gate_matrix, Qubit};

use ndarray::{aview2, Array2};
use num_complex::Complex64;
use smallvec::smallvec;
use smallvec::{smallvec, SmallVec};

use numpy::IntoPyArray;
use numpy::PyReadonlyArray2;
Expand Down Expand Up @@ -482,6 +482,198 @@ impl StandardGate {
pub fn num_ctrl_qubits(&self) -> u32 {
STANDARD_GATE_NUM_CTRL_QUBITS[*self as usize]
}

pub fn inverse(&self, params: &[Param]) -> Option<(StandardGate, SmallVec<[Param; 3]>)> {
match self {
Self::GlobalPhaseGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::GlobalPhaseGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::HGate => Some((Self::HGate, smallvec![])),
Self::IGate => Some((Self::IGate, smallvec![])),
Self::XGate => Some((Self::XGate, smallvec![])),
Self::YGate => Some((Self::YGate, smallvec![])),
Self::ZGate => Some((Self::ZGate, smallvec![])),
Self::PhaseGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::PhaseGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::RGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RGate,
smallvec![multiply_param(&params[0], -1.0, py), params[1].clone()],
)
})),
Self::RXGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RXGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::RYGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RYGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::RZGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RZGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::SGate => Some((Self::SdgGate, smallvec![])),
Self::SdgGate => Some((Self::SGate, smallvec![])),
Self::SXGate => Some((Self::SXdgGate, smallvec![])),
Self::SXdgGate => Some((Self::SXGate, smallvec![])),
Self::TGate => Some((Self::TdgGate, smallvec![])),
Self::TdgGate => Some((Self::TGate, smallvec![])),
Self::UGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::UGate,
smallvec![
multiply_param(&params[0], -1.0, py),
multiply_param(&params[2], -1.0, py),
multiply_param(&params[1], -1.0, py),
],
)
})),
Self::U1Gate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::U1Gate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::U2Gate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::U2Gate,
smallvec![
add_param(&multiply_param(&params[1], -1.0, py), -PI, py),
add_param(&multiply_param(&params[0], -1.0, py), PI, py),
],
)
})),
Self::U3Gate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::U3Gate,
smallvec![
multiply_param(&params[0], -1.0, py),
multiply_param(&params[2], -1.0, py),
multiply_param(&params[1], -1.0, py),
],
)
})),
Self::CHGate => Some((Self::CHGate, smallvec![])),
Self::CXGate => Some((Self::CXGate, smallvec![])),
Self::CYGate => Some((Self::CYGate, smallvec![])),
Self::CZGate => Some((Self::CZGate, smallvec![])),
Self::DCXGate => None, // the inverse in not a StandardGate
Self::ECRGate => Some((Self::ECRGate, smallvec![])),
Self::SwapGate => Some((Self::SwapGate, smallvec![])),
Self::ISwapGate => None, // the inverse in not a StandardGate
Self::CPhaseGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::CPhaseGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::CRXGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::CRXGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::CRYGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::CRYGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::CRZGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::CRZGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::CSGate => Some((Self::CSdgGate, smallvec![])),
Self::CSdgGate => Some((Self::CSGate, smallvec![])),
Self::CSXGate => None, // the inverse in not a StandardGate
Self::CUGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::CUGate,
smallvec![
multiply_param(&params[0], -1.0, py),
multiply_param(&params[2], -1.0, py),
multiply_param(&params[1], -1.0, py),
multiply_param(&params[3], -1.0, py),
],
)
})),
Self::CU1Gate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::CU1Gate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::CU3Gate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::CU3Gate,
smallvec![
multiply_param(&params[0], -1.0, py),
multiply_param(&params[2], -1.0, py),
multiply_param(&params[1], -1.0, py),
],
)
})),
Self::RXXGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RXXGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::RYYGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RYYGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::RZZGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RZZGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::RZXGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::RZXGate,
smallvec![multiply_param(&params[0], -1.0, py)],
)
})),
Self::XXMinusYYGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::XXMinusYYGate,
smallvec![multiply_param(&params[0], -1.0, py), params[1].clone()],
)
})),
Self::XXPlusYYGate => Some(Python::with_gil(|py| -> (Self, SmallVec<[Param; 3]>) {
(
Self::XXPlusYYGate,
smallvec![multiply_param(&params[0], -1.0, py), params[1].clone()],
)
})),
Self::CCXGate => Some((Self::CCXGate, smallvec![])),
Self::CCZGate => Some((Self::CCZGate, smallvec![])),
Self::CSwapGate => Some((Self::CSwapGate, smallvec![])),
Self::RCCXGate => None, // the inverse in not a StandardGate
Self::C3XGate => Some((Self::C3XGate, smallvec![])),
Self::C3SXGate => None, // the inverse in not a StandardGate
Self::RC3XGate => None, // the inverse in not a StandardGate
}
}
}

#[pymethods]
Expand All @@ -504,6 +696,10 @@ impl StandardGate {
self.definition(&params)
}

pub fn _inverse(&self, params: Vec<Param>) -> Option<(StandardGate, SmallVec<[Param; 3]>)> {
self.inverse(&params)
}

#[getter]
pub fn get_num_qubits(&self) -> u32 {
self.num_qubits()
Expand Down
16 changes: 16 additions & 0 deletions test/python/circuit/test_rust_equivalence.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,22 @@ def test_matrix(self):
rs_def = standard_gate._to_matrix(params)
np.testing.assert_allclose(rs_def, py_def)

def test_inverse(self):
"""Test that the inverse is the same in rust space."""
for name, gate_class in self.standard_gates.items():
standard_gate = getattr(gate_class, "_standard_gate", None)
if standard_gate is None:
# gate is not in rust yet
continue

with self.subTest(name=name):
params = [0.1 * (i + 1) for i in range(standard_gate._num_params())]
py_def = gate_class.base_class(*params).inverse()
rs_def = standard_gate._inverse(params)
if rs_def is not None:
self.assertEqual(py_def.name, rs_def[0].name)
np.testing.assert_allclose(py_def.params, rs_def[1])

def test_name(self):
"""Test that the gate name properties match in rust space."""
for name, gate_class in self.standard_gates.items():
Expand Down

0 comments on commit 82d22f1

Please sign in to comment.