mirror of https://github.com/Qiskit/qiskit.git
Add missing equivalences for XX{Plus,Minus}YYGate (#9017)
* Add missing equivalences for XX{Plus,Minus}YYGate These are just copied from the `_define` method on the classes. The equivalence-library tests are updated (since `subTest` doesn't isolate correctly with `testtools`) to print out all the names of the tests being run, so it's clear that the existing test now tests these definitions. * Use default parameters to beat the scoping weirdness Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
72ba2ee259
commit
b45afea036
|
@ -64,6 +64,8 @@ from . import (
|
|||
ZGate,
|
||||
CZGate,
|
||||
CCZGate,
|
||||
XXPlusYYGate,
|
||||
XXMinusYYGate,
|
||||
)
|
||||
|
||||
|
||||
|
@ -1315,3 +1317,73 @@ h_to_rr.append(RGate(theta=pi / 2, phi=pi / 2), [q[0]])
|
|||
h_to_rr.append(RGate(theta=pi, phi=0), [q[0]])
|
||||
h_to_rr.global_phase = pi / 2
|
||||
_sel.add_equivalence(HGate(), h_to_rr)
|
||||
|
||||
# XXPlusYYGate
|
||||
# ┌───────────────┐
|
||||
# ┤0 ├
|
||||
# │ {XX+YY}(θ,β) │
|
||||
# ┤1 ├
|
||||
# └───────────────┘
|
||||
# ┌───────┐ ┌───┐ ┌───┐┌────────────┐┌───┐ ┌─────┐ ┌────────────┐
|
||||
# ─┤ Rz(β) ├──┤ S ├────────────┤ X ├┤ Ry(-0.5*θ) ├┤ X ├──┤ Sdg ├───┤ Rz(-1.0*β) ├───────────
|
||||
# ≡ ┌┴───────┴─┐├───┴┐┌─────────┐└─┬─┘├────────────┤└─┬─┘┌─┴─────┴──┐└──┬──────┬──┘┌─────────┐
|
||||
# ┤ Rz(-π/2) ├┤ √X ├┤ Rz(π/2) ├──■──┤ Ry(-0.5*θ) ├──■──┤ Rz(-π/2) ├───┤ √Xdg ├───┤ Rz(π/2) ├
|
||||
# └──────────┘└────┘└─────────┘ └────────────┘ └──────────┘ └──────┘ └─────────┘
|
||||
q = QuantumRegister(2, "q")
|
||||
xxplusyy = QuantumCircuit(q)
|
||||
beta = Parameter("beta")
|
||||
theta = Parameter("theta")
|
||||
rules = [
|
||||
(RZGate(beta), [q[0]], []),
|
||||
(RZGate(-pi / 2), [q[1]], []),
|
||||
(SXGate(), [q[1]], []),
|
||||
(RZGate(pi / 2), [q[1]], []),
|
||||
(SGate(), [q[0]], []),
|
||||
(CXGate(), [q[1], q[0]], []),
|
||||
(RYGate(-theta / 2), [q[1]], []),
|
||||
(RYGate(-theta / 2), [q[0]], []),
|
||||
(CXGate(), [q[1], q[0]], []),
|
||||
(SdgGate(), [q[0]], []),
|
||||
(RZGate(-pi / 2), [q[1]], []),
|
||||
(SXdgGate(), [q[1]], []),
|
||||
(RZGate(pi / 2), [q[1]], []),
|
||||
(RZGate(-beta), [q[0]], []),
|
||||
]
|
||||
for instr, qargs, cargs in rules:
|
||||
xxplusyy._append(instr, qargs, cargs)
|
||||
_sel.add_equivalence(XXPlusYYGate(theta, beta), xxplusyy)
|
||||
|
||||
# XXMinusYYGate
|
||||
# ┌───────────────┐
|
||||
# ┤0 ├
|
||||
# │ {XX-YY}(θ,β) │
|
||||
# ┤1 ├
|
||||
# └───────────────┘
|
||||
# ┌──────────┐ ┌────┐┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────┐┌─────────┐
|
||||
# ─┤ Rz(-π/2) ├─┤ √X ├┤ Rz(π/2) ├──■───┤ Ry(θ/2) ├────■──┤ Rz(-π/2) ├─┤ √Xdg ├┤ Rz(π/2) ├
|
||||
# ≡ ┌┴──────────┴┐├───┬┘└─────────┘┌─┴─┐┌┴─────────┴─┐┌─┴─┐└─┬─────┬──┘┌┴──────┤└─────────┘
|
||||
# ┤ Rz(-1.0*β) ├┤ S ├────────────┤ X ├┤ Ry(-0.5*θ) ├┤ X ├──┤ Sdg ├───┤ Rz(β) ├───────────
|
||||
# └────────────┘└───┘ └───┘└────────────┘└───┘ └─────┘ └───────┘
|
||||
q = QuantumRegister(2, "q")
|
||||
xxminusyy = QuantumCircuit(q)
|
||||
beta = Parameter("beta")
|
||||
theta = Parameter("theta")
|
||||
rules = [
|
||||
(RZGate(-beta), [q[1]], []),
|
||||
(RZGate(-pi / 2), [q[0]], []),
|
||||
(SXGate(), [q[0]], []),
|
||||
(RZGate(pi / 2), [q[0]], []),
|
||||
(SGate(), [q[1]], []),
|
||||
(CXGate(), [q[0], q[1]], []),
|
||||
(RYGate(theta / 2), [q[0]], []),
|
||||
(RYGate(-theta / 2), [q[1]], []),
|
||||
(CXGate(), [q[0], q[1]], []),
|
||||
(SdgGate(), [q[1]], []),
|
||||
(RZGate(-pi / 2), [q[0]], []),
|
||||
(SXdgGate(), [q[0]], []),
|
||||
(RZGate(pi / 2), [q[0]], []),
|
||||
(RZGate(beta), [q[1]], []),
|
||||
]
|
||||
for instr, qargs, cargs in rules:
|
||||
xxminusyy._append(instr, qargs, cargs)
|
||||
_sel.add_equivalence(XXMinusYYGate(theta, beta), xxminusyy)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Equivalence rules for :class:`.XXPlusYYGate` and :class:`.XXMinusYYGate` are
|
||||
now available in the standard equivalence library shipped with Qiskit Terra.
|
|
@ -16,7 +16,7 @@
|
|||
import inspect
|
||||
|
||||
import numpy as np
|
||||
from ddt import ddt, data, unpack
|
||||
from ddt import ddt, data, idata, unpack
|
||||
|
||||
from qiskit import QuantumCircuit, QuantumRegister
|
||||
from qiskit.quantum_info import Operator
|
||||
|
@ -256,63 +256,57 @@ class TestStandardGates(QiskitTestCase):
|
|||
self.assertTrue(is_identity_matrix(Operator(gate).dot(gate.inverse().definition).data))
|
||||
|
||||
|
||||
@ddt
|
||||
class TestGateEquivalenceEqual(QiskitTestCase):
|
||||
"""Test the decomposition of a gate in terms of other gates
|
||||
yields the same matrix as the hardcoded matrix definition."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
class_list = Gate.__subclasses__() + ControlledGate.__subclasses__()
|
||||
exclude = {
|
||||
"ControlledGate",
|
||||
"DiagonalGate",
|
||||
"UCGate",
|
||||
"MCGupDiag",
|
||||
"MCU1Gate",
|
||||
"UnitaryGate",
|
||||
"HamiltonianGate",
|
||||
"MCPhaseGate",
|
||||
"UCPauliRotGate",
|
||||
"SingleQubitUnitary",
|
||||
"MCXGate",
|
||||
"VariadicZeroParamGate",
|
||||
"ClassicalFunction",
|
||||
"ClassicalElement",
|
||||
"StatePreparation",
|
||||
"LinearFunction",
|
||||
"Commuting2qBlock",
|
||||
}
|
||||
cls._gate_classes = []
|
||||
for aclass in class_list:
|
||||
if aclass.__name__ not in exclude:
|
||||
cls._gate_classes.append(aclass)
|
||||
|
||||
def test_equivalence_phase(self):
|
||||
class_list = Gate.__subclasses__() + ControlledGate.__subclasses__()
|
||||
exclude = {
|
||||
"ControlledGate",
|
||||
"DiagonalGate",
|
||||
"UCGate",
|
||||
"MCGupDiag",
|
||||
"MCU1Gate",
|
||||
"UnitaryGate",
|
||||
"HamiltonianGate",
|
||||
"MCPhaseGate",
|
||||
"UCPauliRotGate",
|
||||
"SingleQubitUnitary",
|
||||
"MCXGate",
|
||||
"VariadicZeroParamGate",
|
||||
"ClassicalFunction",
|
||||
"ClassicalElement",
|
||||
"StatePreparation",
|
||||
"LinearFunction",
|
||||
"Commuting2qBlock",
|
||||
"PauliEvolutionGate",
|
||||
}
|
||||
# Amazingly, Python's scoping rules for class bodies means that this is the closest we can get
|
||||
# to a "natural" comprehension or functional iterable definition:
|
||||
# https://docs.python.org/3/reference/executionmodel.html#resolution-of-names
|
||||
@idata(filter(lambda x, exclude=exclude: x.__name__ not in exclude, class_list))
|
||||
def test_equivalence_phase(self, gate_class):
|
||||
"""Test that the equivalent circuits from the equivalency_library
|
||||
have equal matrix representations"""
|
||||
for gate_class in self._gate_classes:
|
||||
with self.subTest(i=gate_class):
|
||||
n_params = len(_get_free_params(gate_class))
|
||||
params = [0.1 * i for i in range(1, n_params + 1)]
|
||||
if gate_class.__name__ == "RXXGate":
|
||||
params = [np.pi / 2]
|
||||
if gate_class.__name__ in ["MSGate"]:
|
||||
params[0] = 2
|
||||
if gate_class.__name__ in ["PauliGate"]:
|
||||
params = ["IXYZ"]
|
||||
if gate_class.__name__ in ["BooleanExpression"]:
|
||||
params = ["x | y"]
|
||||
if gate_class.__name__ in ["PauliEvolutionGate", "PauliEvolutionGate"]:
|
||||
continue
|
||||
n_params = len(_get_free_params(gate_class))
|
||||
params = [0.1 * i for i in range(1, n_params + 1)]
|
||||
if gate_class.__name__ == "RXXGate":
|
||||
params = [np.pi / 2]
|
||||
if gate_class.__name__ in ["MSGate"]:
|
||||
params[0] = 2
|
||||
if gate_class.__name__ in ["PauliGate"]:
|
||||
params = ["IXYZ"]
|
||||
if gate_class.__name__ in ["BooleanExpression"]:
|
||||
params = ["x | y"]
|
||||
|
||||
gate = gate_class(*params)
|
||||
equiv_lib_list = std_eqlib.get_entry(gate)
|
||||
for ieq, equivalency in enumerate(equiv_lib_list):
|
||||
with self.subTest(msg=gate.name + "_" + str(ieq)):
|
||||
op1 = Operator(gate)
|
||||
op2 = Operator(equivalency)
|
||||
self.assertEqual(op1, op2)
|
||||
gate = gate_class(*params)
|
||||
equiv_lib_list = std_eqlib.get_entry(gate)
|
||||
for ieq, equivalency in enumerate(equiv_lib_list):
|
||||
with self.subTest(msg=gate.name + "_" + str(ieq)):
|
||||
op1 = Operator(gate)
|
||||
op2 = Operator(equivalency)
|
||||
self.assertEqual(op1, op2)
|
||||
|
||||
|
||||
@ddt
|
||||
|
|
Loading…
Reference in New Issue