Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix qpy custom ControlledGate with overloaded _define() #8927

Merged
merged 3 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions qiskit/qpy/binary_io/circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ def _write_custom_operation(file_obj, name, operation, custom_operations):
# state is open, and the definition setter (during a subsequent read) uses the "fully
# excited" control definition only.
has_definition = True
# Build internal definition to support overloaded subclasses by
# calling definition getter on object
operation.definition # pylint: disable=pointless-statement
data = common.data_to_binary(operation._definition, write_circuit)
size = len(data)
num_ctrl_qubits = operation.num_ctrl_qubits
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
fixes:
- |
Fixed an issue in QPY serialization (:func:`~.qpy.dump`) when a custom
:class:`~.ControlledGate` subclass that overloaded the ``_define()``
method to provide a custom definition for the operation. Previously,
this case of operation was not serialized correctly because it wasn't
accounting for using the potentially ``_define()`` method to provide
a definition.
Fixes `#8794 <https://github.com/Qiskit/qiskit-terra/issues/8794>`__
29 changes: 29 additions & 0 deletions test/python/circuit/test_circuit_load_from_qpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from qiskit.test import QiskitTestCase
from qiskit.circuit.qpy_serialization import dump, load
from qiskit.quantum_info.random import random_unitary
from qiskit.circuit.controlledgate import ControlledGate


class TestLoadFromQPY(QiskitTestCase):
Expand Down Expand Up @@ -1054,3 +1055,31 @@ def test_standard_control_gates(self):
qpy_file.seek(0)
new_circuit = load(qpy_file)[0]
self.assertEqual(qc, new_circuit)

def test_controlled_gate_subclass_custom_definition(self):
"""Test controlled gate with overloaded definition.

Reproduce from: https://github.com/Qiskit/qiskit-terra/issues/8794
"""

class CustomCXGate(ControlledGate):
"""Custom CX with overloaded _define."""

def __init__(self, label=None, ctrl_state=None):
super().__init__(
"cx", 2, [], label, num_ctrl_qubits=1, ctrl_state=ctrl_state, base_gate=XGate()
)

def _define(self) -> None:
qc = QuantumCircuit(2, name=self.name)
qc.cx(0, 1)
self.definition = qc

qc = QuantumCircuit(2)
qc.append(CustomCXGate(), [0, 1])
qpy_file = io.BytesIO()
dump(qc, qpy_file)
qpy_file.seek(0)
new_circ = load(qpy_file)[0]
self.assertEqual(qc, new_circ)
self.assertEqual(qc.decompose(), new_circ.decompose())