Skip to content
Merged
6 changes: 5 additions & 1 deletion qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,12 @@ def extend(self, rhs):
if element not in self.cregs:
self.cregs.append(element)

# Copy the circuit data if rhs and self are the same, otherwise the data of rhs is
# appended to both self and rhs resulting in an infinite loop
data = rhs.data.copy() if rhs is self else rhs.data

# Add new gates
for instruction_context in rhs.data:
for instruction_context in data:
self._append(*instruction_context)
return self

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
fixes:
- |
When extending a `QuantumCircuit` instance (extendee) with another circuit (extension),
the circuit is taken via reference. If a circuit is extended with itself that
leads to an infinite loop as extendee and extension are the same.
This bug is resolved by copying the extension if it is the same object as
the extendee.
16 changes: 16 additions & 0 deletions test/python/circuit/test_circuit_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@
class TestCircuitOperations(QiskitTestCase):
"""QuantumCircuit Operations tests."""

def test_adding_self(self):
"""Test that qc += qc finishes, which can be prone to infinite while-loops.

This can occur e.g. when a user tries
>>> other_qc = qc
>>> other_qc += qc # or qc2.extend(qc)
"""
qc = QuantumCircuit(1)
qc.x(0) # must contain at least one operation to end up in a infinite while-loop

# attempt addition, times out if qc is added via reference
qc += qc
Comment thread
Cryoris marked this conversation as resolved.

# finally, qc should contain two X gates
self.assertEqual(['x', 'x'], [x[0].name for x in qc.data])

def test_combine_circuit_common(self):
"""Test combining two circuits with same registers.
"""
Expand Down