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 multiple nested custom controlled gates in QPY (backport #10537) #10578

Merged
merged 1 commit into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions qiskit/qpy/binary_io/circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -970,10 +970,13 @@ def write_circuit(file_obj, circuit, metadata_serializer=None):
new_custom_operations = list(custom_operations.keys())
while new_custom_operations:
operations_to_serialize = new_custom_operations.copy()
new_custom_operations = []
for name in operations_to_serialize:
operation = custom_operations[name]
new_custom_operations = _write_custom_operation(
custom_operations_buffer, name, operation, custom_operations
new_custom_operations.extend(
_write_custom_operation(
custom_operations_buffer, name, operation, custom_operations
)
)

file_obj.write(struct.pack(formats.CUSTOM_CIRCUIT_DEF_HEADER_PACK, len(custom_operations)))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
Fixed a bug in QPY serialization (:mod:`qiskit.qpy`) where multiple controlled custom gates in
a circuit could result in an invalid QPY file that could not be parsed. Fixed `#9746
<https://github.com/Qiskit/qiskit-terra/issues/9746>`__.
25 changes: 25 additions & 0 deletions test/python/circuit/test_circuit_load_from_qpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,31 @@ def test_switch_expr_stress(self):
self.assertEqual(qc.cregs, new_circuit.cregs)
self.assertDeprecatedBitProperties(qc, new_circuit)

def test_multiple_nested_control_custom_definitions(self):
"""Test that circuits with multiple controlled custom gates that in turn depend on custom
gates can be exported successfully when there are several such gates in the outer circuit.
See gh-9746"""
inner_1 = QuantumCircuit(1, name="inner_1")
inner_1.x(0)
inner_2 = QuantumCircuit(1, name="inner_2")
inner_2.y(0)

outer_1 = QuantumCircuit(1, name="outer_1")
outer_1.append(inner_1.to_gate(), [0], [])
outer_2 = QuantumCircuit(1, name="outer_2")
outer_2.append(inner_2.to_gate(), [0], [])

qc = QuantumCircuit(2)
qc.append(outer_1.to_gate().control(1), [0, 1], [])
qc.append(outer_2.to_gate().control(1), [0, 1], [])

with io.BytesIO() as fptr:
dump(qc, fptr)
fptr.seek(0)
new_circuit = load(fptr)[0]
self.assertEqual(qc, new_circuit)
self.assertDeprecatedBitProperties(qc, new_circuit)

def test_qpy_deprecation(self):
"""Test the old import path's deprecations fire."""
with self.assertWarnsRegex(DeprecationWarning, "is deprecated"):
Expand Down