From 4c6eed9b6ad4204b306c51600f0ac0a7e0b81a5a Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 9 Jan 2024 14:23:45 +0000 Subject: [PATCH] Fix broadcasting of `QuantumCircuit.delay` (#11447) The object is supposed to "broadcast" like a gate; one instruction per qubit. This silently did the wrong thing when given a `set` as its argument, previously. --- qiskit/circuit/delay.py | 6 ++-- qiskit/circuit/quantumcircuit.py | 29 ++----------------- .../fix-delay-broadcast-e8762b01dfd7e94f.yaml | 7 +++++ test/python/circuit/test_delay.py | 11 +++++++ 4 files changed, 24 insertions(+), 29 deletions(-) create mode 100644 releasenotes/notes/fix-delay-broadcast-e8762b01dfd7e94f.yaml diff --git a/qiskit/circuit/delay.py b/qiskit/circuit/delay.py index 97bc81099e75..68d76dc03efb 100644 --- a/qiskit/circuit/delay.py +++ b/qiskit/circuit/delay.py @@ -16,6 +16,7 @@ import numpy as np from qiskit.circuit.exceptions import CircuitError from qiskit.circuit.instruction import Instruction +from qiskit.circuit.gate import Gate from qiskit.circuit.parameterexpression import ParameterExpression @@ -29,13 +30,12 @@ def __init__(self, duration, unit="dt"): super().__init__("delay", 1, 0, params=[duration], unit=unit) + broadcast_arguments = Gate.broadcast_arguments + def inverse(self): """Special case. Return self.""" return self - def broadcast_arguments(self, qargs, cargs): - yield [qarg for sublist in qargs for qarg in sublist], [] - def c_if(self, classical, val): raise CircuitError("Conditional Delay is not yet implemented.") diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 4cfc06d153a4..698f04b8513b 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -3351,32 +3351,9 @@ def delay( Raises: CircuitError: if arguments have bad format. """ - qubits: list[QubitSpecifier] = [] - if qarg is None: # -> apply delays to all qubits - for q in self.qubits: - qubits.append(q) - else: - if isinstance(qarg, QuantumRegister): - qubits.extend([qarg[j] for j in range(qarg.size)]) - elif isinstance(qarg, list): - qubits.extend(qarg) - elif isinstance(qarg, (range, tuple)): - qubits.extend(list(qarg)) - elif isinstance(qarg, slice): - qubits.extend(self.qubits[qarg]) - else: - qubits.append(qarg) - - instructions = InstructionSet( - resource_requester=self._current_scope().resolve_classical_resource - ) - for q in qubits: - inst: tuple[ - Instruction, Sequence[QubitSpecifier] | None, Sequence[ClbitSpecifier] | None - ] = (Delay(duration, unit), [q], []) - self.append(*inst) - instructions.add(*inst) - return instructions + if qarg is None: + qarg = self.qubits + return self.append(Delay(duration, unit=unit), [qarg], []) def h(self, qubit: QubitSpecifier) -> InstructionSet: """Apply :class:`~qiskit.circuit.library.HGate`. diff --git a/releasenotes/notes/fix-delay-broadcast-e8762b01dfd7e94f.yaml b/releasenotes/notes/fix-delay-broadcast-e8762b01dfd7e94f.yaml new file mode 100644 index 000000000000..2facbc643c14 --- /dev/null +++ b/releasenotes/notes/fix-delay-broadcast-e8762b01dfd7e94f.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + The qubit-argument broadcasting of :meth:`.QuantumCircuit.delay` now correctly produces + individual :class:`~.circuit.Delay` instructions for each qubit, as intended. Previously, when + given certain iterables (such as :class:`set`\ s), it would instead silently produce an invalid + circuit that might fail in unusual locations. diff --git a/test/python/circuit/test_delay.py b/test/python/circuit/test_delay.py index e4b0c0193308..f7b1d3f770d8 100644 --- a/test/python/circuit/test_delay.py +++ b/test/python/circuit/test_delay.py @@ -82,6 +82,17 @@ def test_add_delay_on_multiple_qubits_to_circuit(self): expected.delay(300, 2) self.assertEqual(qc, expected) + def test_delay_set(self): + """Test that a set argument to `delay` works.""" + qc = QuantumCircuit(5) + qc.delay(8, {0, 1, 3, 4}) + expected = QuantumCircuit(5) + expected.delay(8, 0) + expected.delay(8, 1) + expected.delay(8, 3) + expected.delay(8, 4) + self.assertEqual(qc, expected) + def test_to_matrix_return_identity_matrix(self): actual = np.array(Delay(100)) expected = np.array([[1, 0], [0, 1]], dtype=complex)