From 0e2c588cc8c92dbc66b5d38fc1297ae3be32abde Mon Sep 17 00:00:00 2001 From: Kevin Krsulich Date: Mon, 21 Jun 2021 17:30:58 -0400 Subject: [PATCH 1/4] Deprecate 'id' instructions on IBM Quantum hardware. --- qiskit/providers/ibmq/ibmqbackend.py | 98 ++++++++++++++++++- ...ware-id-instructions-5166323103eefdc4.yaml | 11 +++ test/ibmq/test_ibmq_backend.py | 35 ++++++- 3 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/deprecate-hardware-id-instructions-5166323103eefdc4.yaml diff --git a/qiskit/providers/ibmq/ibmqbackend.py b/qiskit/providers/ibmq/ibmqbackend.py index e0c71a011..4e48a7383 100644 --- a/qiskit/providers/ibmq/ibmqbackend.py +++ b/qiskit/providers/ibmq/ibmqbackend.py @@ -20,7 +20,8 @@ from datetime import datetime as python_datetime from qiskit.compiler import assemble -from qiskit.circuit import QuantumCircuit, Parameter +from qiskit.circuit import QuantumCircuit, Parameter, Delay +from qiskit.circuit.duration import duration_in_dt from qiskit.pulse import Schedule, LoConfig from qiskit.pulse.channels import PulseChannel from qiskit.qobj import QasmQobj, PulseQobj, validate_qobj_against_schema @@ -102,6 +103,7 @@ class IBMQBackend(Backend): """ qobj_warning_issued = False + id_warning_issued = False def __init__( self, @@ -286,6 +288,9 @@ def run( "'use_measure_esp' is unset or set to 'False'." ) + if sim_method is None: + self._deprecate_id_instruction(circuits) + if isinstance(circuits, (QasmQobj, PulseQobj)): if not self.qobj_warning_issued: warnings.warn("Passing a Qobj to Backend.run is deprecated and will " @@ -746,6 +751,97 @@ def __repr__(self) -> str: return "<{}('{}') from IBMQ({})>".format( self.__class__.__name__, self.name(), credentials_info) + def _deprecate_id_instruction( + self, + circuits: Union[QasmQobj, PulseQobj, QuantumCircuit, Schedule, + List[Union[QuantumCircuit, Schedule]]] + ) -> None: + """Raise a DeprecationWarning if any circuit contains an 'id' instruction. + + Additionally, if 'delay' is a 'supported_instruction', replace each 'id' + instruction (in-place) with the equivalent ('sx'-length) 'delay' instruction. + + Args: + circuits: The individual or list of :class:`~qiskit.circuits.QuantumCircuit` or + :class:`~qiskit.pulse.Schedule` objects passed to + :meth:`IBMQBackend.run()`. Modified in-place. + + Returns: + None + """ + + if isinstance(circuits, PulseQobj): + return + + id_support = 'id' in getattr(self.configuration(), 'basis_gates', []) + delay_support = 'delay' in getattr(self.configuration(), 'supported_instructions', []) + + if isinstance(circuits, QasmQobj): + circuit_has_id = any(instr.name == 'id' + for experiment in circuits.experiments + for instr in experiment.instructions) + else: + if not isinstance(circuits, List): + circuits = [circuits] + + circuit_has_id = any(instr.name == 'id' + for circuit in circuits + if isinstance(circuit, QuantumCircuit) + for instr, qargs, cargs in circuit.data) + + if not circuit_has_id: + return + + if not self.id_warning_issued: + if id_support: + warnings.warn("Support for the 'id' instruction has been deprecated " + "from IBM hardware backends. Any 'id' instructions " + "will be replaced with their equivalent 'delay' instruction. " + "Please use the 'delay' instruction instead.", DeprecationWarning, + stacklevel=4) + elif delay_support: + warnings.warn("Support for the 'id' instruction has been removed " + "from IBM hardware backends. Any 'id' instructions " + "will be replaced with their equivalent 'delay' instruction. " + "Please use the 'delay' instruction instead.", DeprecationWarning, + stacklevel=4) + else: + warnings.warn("Support for the 'id' instruction has been removed " + "from IBM hardware backends. Please use the 'delay' " + "instruction instead.", DeprecationWarning, + stacklevel=4) + + self.id_warning_issued = True + + if not delay_support: + return + + dt_in_s = self.configuration().dt + + if isinstance(circuits, QasmQobj): + for experiment in circuits.experiments: + for instr in experiment.instructions: + if instr.name == 'id': + sx_duration = self.properties().gate_length('sx', instr.qubits[0]) + sx_duration_in_dt = duration_in_dt(sx_duration, dt_in_s) + + instr.name = 'delay' + instr.params = [sx_duration_in_dt] + else: + for circuit in circuits: + if isinstance(circuit, Schedule): + continue + + for idx, (instr, qargs, cargs) in enumerate(circuit.data): + if instr.name == 'id': + + sx_duration = self.properties().gate_length('sx', qargs[0].index) + sx_duration_in_dt = duration_in_dt(sx_duration, dt_in_s) + + delay_instr = Delay(sx_duration_in_dt) + + circuit.data[idx] = (delay_instr, qargs, cargs) + class IBMQSimulator(IBMQBackend): """Backend class interfacing with an IBM Quantum Experience simulator.""" diff --git a/releasenotes/notes/deprecate-hardware-id-instructions-5166323103eefdc4.yaml b/releasenotes/notes/deprecate-hardware-id-instructions-5166323103eefdc4.yaml new file mode 100644 index 000000000..397edc668 --- /dev/null +++ b/releasenotes/notes/deprecate-hardware-id-instructions-5166323103eefdc4.yaml @@ -0,0 +1,11 @@ +--- +deprecations: + - | + The `id` instruction has been deprecated on IBM hardware + backends. Instead, please use the `delay` instruction which + implements variable-length delays, specified in units of + `dt`. When running a circuit containing an `id` instruction, + a warning will be raised on job submission and any `id` + instructions in the job will be automatically replaced with their + equivalent `delay` instruction. + diff --git a/test/ibmq/test_ibmq_backend.py b/test/ibmq/test_ibmq_backend.py index d6934b84b..f9bbd73c7 100644 --- a/test/ibmq/test_ibmq_backend.py +++ b/test/ibmq/test_ibmq_backend.py @@ -16,8 +16,10 @@ from datetime import timedelta, datetime import warnings from unittest import SkipTest +from unittest.mock import patch -from qiskit import transpile, assemble +from qiskit import QuantumCircuit, transpile, assemble +from qiskit.providers.models import QasmBackendConfiguration from qiskit.test.reference_circuits import ReferenceCircuits from qiskit.providers.ibmq.ibmqbackend import IBMQBackend from qiskit.providers.ibmq.ibmqbackendservice import IBMQBackendService @@ -176,6 +178,37 @@ def test_sim_backend_options(self): self.assertTrue(qobj.config.memory) self.assertEqual(qobj.config.foo, 'foo') + def test_deprecate_id_instruction(self): + """Test replacement of 'id' Instructions with 'Delay' instructions.""" + + circuit_with_id = QuantumCircuit(2) + circuit_with_id.id(0) + circuit_with_id.id(0) + circuit_with_id.id(1) + + config = QasmBackendConfiguration( + basis_gates=['id'], + supported_instructions=['delay'], + dt=0.25, + backend_name='test', + backend_version=0.0, + n_qubits=1, + gates=[], + local=False, + simulator=False, + conditional=False, + open_pulse=False, + memory=False, + max_shots=1, + coupling_map=None, + ) + + with patch.object(self.backend, 'configuration', return_value=config): + with self.assertWarnsRegex(DeprecationWarning, r"'id' instruction"): + self.backend._deprecate_id_instruction(circuit_with_id) + + self.assertEqual(circuit_with_id.count_ops(), {'delay': 3}) + class TestIBMQBackendService(IBMQTestCase): """Test ibmqbackendservice module.""" From ab304e4f65341e11fb3c5a851618d54d4c677f83 Mon Sep 17 00:00:00 2001 From: Kevin Krsulich Date: Tue, 6 Jul 2021 17:09:25 -0400 Subject: [PATCH 2/4] Apply suggestions from code review. Co-authored-by: Jessie Yu --- qiskit/providers/ibmq/ibmqbackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/providers/ibmq/ibmqbackend.py b/qiskit/providers/ibmq/ibmqbackend.py index 4e48a7383..caa5cbc69 100644 --- a/qiskit/providers/ibmq/ibmqbackend.py +++ b/qiskit/providers/ibmq/ibmqbackend.py @@ -288,7 +288,7 @@ def run( "'use_measure_esp' is unset or set to 'False'." ) - if sim_method is None: + if not self.configuration().simulator: self._deprecate_id_instruction(circuits) if isinstance(circuits, (QasmQobj, PulseQobj)): From 62b1af0838fe010dca3ef097d281fa155cace2d2 Mon Sep 17 00:00:00 2001 From: Kevin Krsulich Date: Tue, 6 Jul 2021 17:12:19 -0400 Subject: [PATCH 3/4] Update qiskit/providers/ibmq/ibmqbackend.py --- qiskit/providers/ibmq/ibmqbackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/providers/ibmq/ibmqbackend.py b/qiskit/providers/ibmq/ibmqbackend.py index caa5cbc69..da9255799 100644 --- a/qiskit/providers/ibmq/ibmqbackend.py +++ b/qiskit/providers/ibmq/ibmqbackend.py @@ -793,7 +793,7 @@ def _deprecate_id_instruction( return if not self.id_warning_issued: - if id_support: + if id_support and delay_support: warnings.warn("Support for the 'id' instruction has been deprecated " "from IBM hardware backends. Any 'id' instructions " "will be replaced with their equivalent 'delay' instruction. " From fa5fa300244cdcbf49abd8ce8e7893348f01a093 Mon Sep 17 00:00:00 2001 From: Kevin Krsulich Date: Tue, 6 Jul 2021 17:24:06 -0400 Subject: [PATCH 4/4] Only show DeprecationWarning if device supports 'delay'. --- qiskit/providers/ibmq/ibmqbackend.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/qiskit/providers/ibmq/ibmqbackend.py b/qiskit/providers/ibmq/ibmqbackend.py index da9255799..a175933a4 100644 --- a/qiskit/providers/ibmq/ibmqbackend.py +++ b/qiskit/providers/ibmq/ibmqbackend.py @@ -776,6 +776,9 @@ def _deprecate_id_instruction( id_support = 'id' in getattr(self.configuration(), 'basis_gates', []) delay_support = 'delay' in getattr(self.configuration(), 'supported_instructions', []) + if not delay_support: + return + if isinstance(circuits, QasmQobj): circuit_has_id = any(instr.name == 'id' for experiment in circuits.experiments @@ -799,23 +802,15 @@ def _deprecate_id_instruction( "will be replaced with their equivalent 'delay' instruction. " "Please use the 'delay' instruction instead.", DeprecationWarning, stacklevel=4) - elif delay_support: + else: warnings.warn("Support for the 'id' instruction has been removed " "from IBM hardware backends. Any 'id' instructions " "will be replaced with their equivalent 'delay' instruction. " "Please use the 'delay' instruction instead.", DeprecationWarning, stacklevel=4) - else: - warnings.warn("Support for the 'id' instruction has been removed " - "from IBM hardware backends. Please use the 'delay' " - "instruction instead.", DeprecationWarning, - stacklevel=4) self.id_warning_issued = True - if not delay_support: - return - dt_in_s = self.configuration().dt if isinstance(circuits, QasmQobj):