diff --git a/qiskit/providers/ibmq/ibmqbackend.py b/qiskit/providers/ibmq/ibmqbackend.py index e0c71a011..a175933a4 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 not self.configuration().simulator: + 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,92 @@ 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 not delay_support: + return + + 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 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. " + "Please use the 'delay' instruction instead.", DeprecationWarning, + stacklevel=4) + 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) + + self.id_warning_issued = True + + 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."""