From acf814b9bb644d550b3b549903bd18e2eeaaf4b6 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Sun, 10 Sep 2023 11:55:20 +0000 Subject: [PATCH 1/5] Removed code related to Schedule, qubit_lo_freq, mea_lo_freq, schedule_los --- qiskit_ibm_provider/ibm_backend.py | 47 +++----------------- qiskit_ibm_provider/job/ibm_circuit_job.py | 7 ++- qiskit_ibm_provider/job/ibm_composite_job.py | 11 +++-- qiskit_ibm_provider/job/ibm_job.py | 7 ++- qiskit_ibm_provider/utils/options.py | 9 ---- test/integration/test_backend.py | 40 ----------------- test/integration/test_serialization.py | 2 - 7 files changed, 17 insertions(+), 106 deletions(-) diff --git a/qiskit_ibm_provider/ibm_backend.py b/qiskit_ibm_provider/ibm_backend.py index e7055616e..58665efc0 100644 --- a/qiskit_ibm_provider/ibm_backend.py +++ b/qiskit_ibm_provider/ibm_backend.py @@ -30,7 +30,6 @@ PulseBackendConfiguration, ) from qiskit.providers.options import Options -from qiskit.pulse import Schedule, LoConfig from qiskit.pulse.channels import ( PulseChannel, AcquireChannel, @@ -143,8 +142,6 @@ class IBMBackend(Backend): * n_uchannels: Number of u-channels. * u_channel_lo: U-channel relationship on device los. * meas_levels: Supported measurement levels. - * qubit_lo_range: Qubit lo ranges for each qubit with form (min, max) in GHz. - * meas_lo_range: Measurement lo ranges for each qubit with form (min, max) in GHz. * dt: Qubit drive channel timestep in nanoseconds. * dtm: Measurement drive channel timestep in nanoseconds. * rep_times: Supported repetition times (program execution time) for backend in μs. @@ -333,7 +330,7 @@ def target_history(self, datetime: Optional[python_datetime] = None) -> Target: def run( self, circuits: Union[ - QuantumCircuit, Schedule, str, List[Union[QuantumCircuit, Schedule, str]] + QuantumCircuit, str, List[Union[QuantumCircuit, str]] ], dynamic: bool = None, job_tags: Optional[List[str]] = None, @@ -342,14 +339,6 @@ def run( header: Optional[Dict] = None, shots: Optional[Union[int, float]] = None, memory: Optional[bool] = None, - qubit_lo_freq: Optional[List[int]] = None, - meas_lo_freq: Optional[List[int]] = None, - schedule_los: Optional[ - Union[ - List[Union[Dict[PulseChannel, float], LoConfig]], - Union[Dict[PulseChannel, float], LoConfig], - ] - ] = None, meas_level: Optional[Union[int, MeasLevel]] = None, meas_return: Optional[Union[str, MeasReturnType]] = None, rep_delay: Optional[float] = None, @@ -366,10 +355,6 @@ def run( Args: circuits: An individual or a list of :class:`~qiskit.circuits.QuantumCircuit`. - :class:`~qiskit.pulse.Schedule` is no longer supported. Use ``pulse gates`` instead. - See `tutorial - `_ - on how to use pulse gates. dynamic: Whether the circuit is dynamic (uses in-circuit conditionals) job_tags: Tags to be assigned to the job. The tags can subsequently be used as a filter in the :meth:`jobs()` function call. @@ -389,14 +374,6 @@ def run( memory: If ``True``, per-shot measurement bitstrings are returned as well (provided the backend supports it). For OpenPulse jobs, only measurement level 2 supports this option. - qubit_lo_freq: List of default qubit LO frequencies in Hz. Will be overridden by - ``schedule_los`` if set. - meas_lo_freq: List of default measurement LO frequencies in Hz. Will be overridden - by ``schedule_los`` if set. - schedule_los: Experiment LO configurations, frequencies are given in Hz. - meas_level: Level of the measurement output for pulse experiments. See - `OpenPulse specification `_ for details: - * ``0``, measurements of the raw signal (the measurement output pulse envelope) * ``1``, measurement kernel is selected (a complex number obtained after applying the measurement kernel to the measurement output signal) @@ -498,9 +475,6 @@ def run( header=header, shots=shots, memory=memory, - qubit_lo_freq=qubit_lo_freq, - meas_lo_freq=meas_lo_freq, - schedule_los=schedule_los, meas_level=meas_level, meas_return=meas_return, rep_delay=rep_delay, @@ -769,17 +743,16 @@ def __repr__(self) -> str: return "<{}('{}')>".format(self.__class__.__name__, self.name) def _deprecate_id_instruction( - self, circuits: List[Union[QuantumCircuit, Schedule]] - ) -> List[Union[QuantumCircuit, Schedule]]: + self, circuits: List[QuantumCircuit] + ) -> List[QuantumCircuit]: """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:`IBMBackend.run()`. Modified in-place. + circuits: The individual or list of :class:`~qiskit.circuits.QuantumCircuit` + passed to :meth:`IBMBackend.run()`. Modified in-place. Returns: A modified copy of the original circuit where 'id' instructions are replaced with @@ -844,22 +817,14 @@ def _check_circuits_attributes(self, circuits: List[QuantumCircuit]) -> None: """Check that circuits can be executed on backend. Raises: IBMBackendValueError: - - If Schedule is given as an input circuit. - If one of the circuits contains more qubits than on the backend.""" - schedule_error_msg = ( - "Class 'Schedule' is no longer supported as an input circuit. " - "Use 'pulse gates' instead. See `tutorial " - "https://qiskit.org/documentation/tutorials/circuits_advanced/05_pulse_gates.html` " - "on how to use pulse gates." - ) + if len(circuits) > self._max_circuits: raise IBMBackendValueError( f"Number of circuits, {len(circuits)} exceeds the " f"maximum for this backend, {self._max_circuits})" ) for circ in circuits: - if isinstance(circ, Schedule): - raise IBMBackendValueError(schedule_error_msg) if isinstance(circ, QuantumCircuit): if circ.num_qubits > self._configuration.num_qubits: raise IBMBackendValueError( diff --git a/qiskit_ibm_provider/job/ibm_circuit_job.py b/qiskit_ibm_provider/job/ibm_circuit_job.py index 0a7b2d63c..fb2182505 100644 --- a/qiskit_ibm_provider/job/ibm_circuit_job.py +++ b/qiskit_ibm_provider/job/ibm_circuit_job.py @@ -27,7 +27,6 @@ from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.result import Result -from qiskit.pulse import Schedule from qiskit_ibm_provider import ibm_backend # pylint: disable=unused-import from .constants import IBM_COMPOSITE_JOB_TAG_PREFIX, IBM_MANAGED_JOB_ID_PREFIX @@ -611,11 +610,11 @@ def header(self) -> Dict: return self._params.get("header") return {} - def circuits(self) -> List[Union[QuantumCircuit, Schedule]]: - """Return the circuits or pulse schedules for this job. + def circuits(self) -> List[QuantumCircuit]: + """Return the circuits for this job. Returns: - The circuits or pulse schedules for this job. An empty list + The circuits or for this job. An empty list is returned if the circuits cannot be retrieved (for example, if the job uses an old format that is no longer supported). """ diff --git a/qiskit_ibm_provider/job/ibm_composite_job.py b/qiskit_ibm_provider/job/ibm_composite_job.py index 0f5e96da0..4462f5fa7 100644 --- a/qiskit_ibm_provider/job/ibm_composite_job.py +++ b/qiskit_ibm_provider/job/ibm_composite_job.py @@ -30,7 +30,6 @@ from qiskit.compiler import assemble from qiskit.providers.jobstatus import JOB_FINAL_STATES, JobStatus from qiskit.providers.models import BackendProperties -from qiskit.pulse import Schedule from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result from qiskit.result.models import ExperimentResult @@ -126,7 +125,7 @@ def __init__( creation_date: Optional[datetime] = None, jobs: Optional[List[IBMCircuitJob]] = None, circuits_list: Optional[ - List[Union[List[QuantumCircuit], List[Schedule]]] + List[List[QuantumCircuit]] ] = None, run_config: Optional[Dict] = None, name: Optional[str] = None, @@ -259,7 +258,7 @@ def from_jobs( def _submit_circuits( self, - circuit_lists: List[Union[List[QuantumCircuit], List[Schedule]]], + circuit_lists: List[List[QuantumCircuit]], run_config: Dict, ) -> None: """Assemble and submit circuits. @@ -873,11 +872,11 @@ def refresh(self) -> None: if job.status() not in JOB_FINAL_STATES: job.refresh() - def circuits(self) -> List[Union[QuantumCircuit, Schedule]]: - """Return the circuits or pulse schedules for this job. + def circuits(self) -> List[QuantumCircuit]: + """Return the circuits for this job. Returns: - The circuits or pulse schedules for this job. + The circuits for this job. """ if not self._circuits: qobj = self._get_qobj() diff --git a/qiskit_ibm_provider/job/ibm_job.py b/qiskit_ibm_provider/job/ibm_job.py index 8019be4ab..82c13f25f 100644 --- a/qiskit_ibm_provider/job/ibm_job.py +++ b/qiskit_ibm_provider/job/ibm_job.py @@ -20,7 +20,6 @@ from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.providers.job import JobV1 as Job from qiskit.providers.models import BackendProperties -from qiskit.pulse import Schedule from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result @@ -198,11 +197,11 @@ def refresh(self) -> None: """Obtain the latest job information from the server.""" pass - def circuits(self) -> List[Union[QuantumCircuit, Schedule]]: - """Return the circuits or pulse schedules for this job. + def circuits(self) -> List[QuantumCircuit]: + """Return the circuits for this job. Returns: - The circuits or pulse schedules for this job. An empty list + The circuits for this job. An empty list is returned if the circuits cannot be retrieved (for example, if the job uses an old format that is no longer supported). """ diff --git a/qiskit_ibm_provider/utils/options.py b/qiskit_ibm_provider/utils/options.py index 9162dfb80..33465a2e7 100644 --- a/qiskit_ibm_provider/utils/options.py +++ b/qiskit_ibm_provider/utils/options.py @@ -15,7 +15,6 @@ from dataclasses import asdict, dataclass from typing import Dict, List, Union, Any, Optional from qiskit.circuit import QuantumCircuit -from qiskit.pulse import LoConfig from qiskit.pulse.channels import PulseChannel from qiskit.qobj.utils import MeasLevel, MeasReturnType @@ -53,14 +52,6 @@ class QASM2Options(CommonOptions): """Options for the QASM2 path.""" header: Optional[Dict] = None - qubit_lo_freq: Optional[List[int]] = None - meas_lo_freq: Optional[List[int]] = None - schedule_los: Optional[ - Union[ - List[Union[Dict[PulseChannel, float], LoConfig]], - Union[Dict[PulseChannel, float], LoConfig], - ] - ] = None init_qubits: bool = True use_measure_esp: Optional[bool] = None # Simulator only diff --git a/test/integration/test_backend.py b/test/integration/test_backend.py index 38cc4895b..3dfaade8e 100644 --- a/test/integration/test_backend.py +++ b/test/integration/test_backend.py @@ -19,7 +19,6 @@ from qiskit.providers.models import QasmBackendConfiguration from qiskit.providers.exceptions import QiskitBackendNotFoundError from qiskit.test.reference_circuits import ReferenceCircuits -from qiskit.pulse import Schedule from qiskit_ibm_provider import IBMBackend, IBMProvider, least_busy from qiskit_ibm_provider.ibm_qubit_properties import IBMQubitProperties @@ -31,7 +30,6 @@ production_only, ) from ..ibm_test_case import IBMTestCase -from ..utils import get_pulse_schedule, cancel_job class TestIBMBackend(IBMTestCase): @@ -87,33 +85,6 @@ def test_backend_pulse_defaults(self): if backend.configuration().open_pulse: self.assertIsNotNone(defaults) - @skip("See Terra issue #9488") - def test_backend_options(self): - """Test backend options.""" - provider: IBMProvider = self.backend.provider - backends = provider.backends( - open_pulse=True, - operational=True, - instance=self.dependencies.instance, - ) - if not backends: - raise SkipTest("Skipping pulse test since no pulse backend found.") - - backend = backends[0] - backend.options.shots = 2048 - backend.set_options( - qubit_lo_freq=[4.9e9, 5.0e9], meas_lo_freq=[6.5e9, 6.6e9], meas_level=2 - ) - job = backend.run(get_pulse_schedule(backend), meas_level=1, foo="foo") - backend_options = provider.backend.retrieve_job(job.job_id()).backend_options() - self.assertEqual(backend_options["shots"], 2048) - # Qobj config freq is in GHz. - self.assertAlmostEqual(backend_options["qubit_lo_freq"], [4.9e9, 5.0e9]) - self.assertEqual(backend_options["meas_lo_freq"], [6.5e9, 6.6e9]) - self.assertEqual(backend_options["meas_level"], 1) - self.assertEqual(backend_options["foo"], "foo") - cancel_job(job) - def test_sim_backend_options(self): """Test simulator backend options.""" provider: IBMProvider = self.backend.provider @@ -201,17 +172,6 @@ def test_retrieve_backend_not_exist(self): with self.assertRaises(QiskitBackendNotFoundError): self.dependencies.provider.get_backend("nonexistent_backend") - def test_schedule_error_message(self): - """Test that passing a Schedule as input to Backend.run() raises an error.""" - backend = self.dependencies.provider.get_backend("ibmq_qasm_simulator") - schedule = Schedule() - for circuit in [schedule, [schedule]]: - with self.assertRaises(IBMBackendValueError) as err: - backend.run(circuit) - self.assertIn( - "Class 'Schedule' is no longer supported as an input circuit", - str(err.exception), - ) def test_too_many_qubits_in_circuit(self): """Check error message if circuit contains more qubits than supported on the backend.""" diff --git a/test/integration/test_serialization.py b/test/integration/test_serialization.py index f00cd4f83..cb823d015 100644 --- a/test/integration/test_serialization.py +++ b/test/integration/test_serialization.py @@ -82,8 +82,6 @@ def test_backend_configuration(self): # Known keys that look like a serialized complex number. good_keys = ( "coupling_map", - "qubit_lo_range", - "meas_lo_range", "gates.coupling_map", "meas_levels", "qubit_channel_mapping", From 2fda263dd6d375fe0bc01077e28fcf4f361421b9 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Sun, 10 Sep 2023 12:11:00 +0000 Subject: [PATCH 2/5] black and lint --- qiskit_ibm_provider/ibm_backend.py | 5 +---- qiskit_ibm_provider/job/ibm_circuit_job.py | 2 +- qiskit_ibm_provider/job/ibm_composite_job.py | 4 +--- qiskit_ibm_provider/utils/options.py | 3 +-- test/integration/test_backend.py | 3 +-- 5 files changed, 5 insertions(+), 12 deletions(-) diff --git a/qiskit_ibm_provider/ibm_backend.py b/qiskit_ibm_provider/ibm_backend.py index 58665efc0..20514f5f1 100644 --- a/qiskit_ibm_provider/ibm_backend.py +++ b/qiskit_ibm_provider/ibm_backend.py @@ -31,7 +31,6 @@ ) from qiskit.providers.options import Options from qiskit.pulse.channels import ( - PulseChannel, AcquireChannel, ControlChannel, DriveChannel, @@ -329,9 +328,7 @@ def target_history(self, datetime: Optional[python_datetime] = None) -> Target: def run( self, - circuits: Union[ - QuantumCircuit, str, List[Union[QuantumCircuit, str]] - ], + circuits: Union[QuantumCircuit, str, List[Union[QuantumCircuit, str]]], dynamic: bool = None, job_tags: Optional[List[str]] = None, init_circuit: Optional[QuantumCircuit] = None, diff --git a/qiskit_ibm_provider/job/ibm_circuit_job.py b/qiskit_ibm_provider/job/ibm_circuit_job.py index fb2182505..483b08a5c 100644 --- a/qiskit_ibm_provider/job/ibm_circuit_job.py +++ b/qiskit_ibm_provider/job/ibm_circuit_job.py @@ -18,7 +18,7 @@ import queue from concurrent import futures from datetime import datetime -from typing import Dict, Optional, Any, List, Union +from typing import Dict, Optional, Any, List import re import requests diff --git a/qiskit_ibm_provider/job/ibm_composite_job.py b/qiskit_ibm_provider/job/ibm_composite_job.py index 4462f5fa7..8eb305f8b 100644 --- a/qiskit_ibm_provider/job/ibm_composite_job.py +++ b/qiskit_ibm_provider/job/ibm_composite_job.py @@ -124,9 +124,7 @@ def __init__( job_id: Optional[str] = None, creation_date: Optional[datetime] = None, jobs: Optional[List[IBMCircuitJob]] = None, - circuits_list: Optional[ - List[List[QuantumCircuit]] - ] = None, + circuits_list: Optional[List[List[QuantumCircuit]]] = None, run_config: Optional[Dict] = None, name: Optional[str] = None, tags: Optional[List[str]] = None, diff --git a/qiskit_ibm_provider/utils/options.py b/qiskit_ibm_provider/utils/options.py index 33465a2e7..34874dfdb 100644 --- a/qiskit_ibm_provider/utils/options.py +++ b/qiskit_ibm_provider/utils/options.py @@ -13,9 +13,8 @@ """Backend run options.""" from dataclasses import asdict, dataclass -from typing import Dict, List, Union, Any, Optional +from typing import Dict, Union, Any, Optional from qiskit.circuit import QuantumCircuit -from qiskit.pulse.channels import PulseChannel from qiskit.qobj.utils import MeasLevel, MeasReturnType diff --git a/test/integration/test_backend.py b/test/integration/test_backend.py index 3dfaade8e..e809033ab 100644 --- a/test/integration/test_backend.py +++ b/test/integration/test_backend.py @@ -12,7 +12,7 @@ """IBMBackend Test.""" -from unittest import SkipTest, mock, skip +from unittest import mock, skip from unittest.mock import patch from qiskit import QuantumCircuit, transpile @@ -172,7 +172,6 @@ def test_retrieve_backend_not_exist(self): with self.assertRaises(QiskitBackendNotFoundError): self.dependencies.provider.get_backend("nonexistent_backend") - def test_too_many_qubits_in_circuit(self): """Check error message if circuit contains more qubits than supported on the backend.""" backends = self.dependencies.provider.backends( From 8113e40a437bee1b1b4a26fffe3ac1032a73e880 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Sun, 10 Sep 2023 12:25:14 +0000 Subject: [PATCH 3/5] Returned lines in documentation that were removed by mistake --- qiskit_ibm_provider/ibm_backend.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qiskit_ibm_provider/ibm_backend.py b/qiskit_ibm_provider/ibm_backend.py index 20514f5f1..e2052e468 100644 --- a/qiskit_ibm_provider/ibm_backend.py +++ b/qiskit_ibm_provider/ibm_backend.py @@ -371,6 +371,9 @@ def run( memory: If ``True``, per-shot measurement bitstrings are returned as well (provided the backend supports it). For OpenPulse jobs, only measurement level 2 supports this option. + meas_level: Level of the measurement output for pulse experiments. See + `OpenPulse specification `_ for details: + * ``0``, measurements of the raw signal (the measurement output pulse envelope) * ``1``, measurement kernel is selected (a complex number obtained after applying the measurement kernel to the measurement output signal) From 954e83226a17b45ec55de72d4f1d2440629acc10 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Sun, 10 Sep 2023 12:48:29 +0000 Subject: [PATCH 4/5] Fixed documentation --- qiskit_ibm_provider/ibm_backend.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qiskit_ibm_provider/ibm_backend.py b/qiskit_ibm_provider/ibm_backend.py index e2052e468..87a5c3295 100644 --- a/qiskit_ibm_provider/ibm_backend.py +++ b/qiskit_ibm_provider/ibm_backend.py @@ -141,6 +141,8 @@ class IBMBackend(Backend): * n_uchannels: Number of u-channels. * u_channel_lo: U-channel relationship on device los. * meas_levels: Supported measurement levels. + * qubit_lo_range: Qubit lo ranges for each qubit with form (min, max) in GHz. + * meas_lo_range: Measurement lo ranges for each qubit with form (min, max) in GHz. * dt: Qubit drive channel timestep in nanoseconds. * dtm: Measurement drive channel timestep in nanoseconds. * rep_times: Supported repetition times (program execution time) for backend in μs. From 6c29b998d9f4b6e2dc9d139b1b218928b00a621e Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Sun, 10 Sep 2023 12:59:20 +0000 Subject: [PATCH 5/5] Put back range parameters --- test/integration/test_serialization.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/integration/test_serialization.py b/test/integration/test_serialization.py index cb823d015..f00cd4f83 100644 --- a/test/integration/test_serialization.py +++ b/test/integration/test_serialization.py @@ -82,6 +82,8 @@ def test_backend_configuration(self): # Known keys that look like a serialized complex number. good_keys = ( "coupling_map", + "qubit_lo_range", + "meas_lo_range", "gates.coupling_map", "meas_levels", "qubit_channel_mapping",