diff --git a/docs/tutorials/03_backends.ipynb b/docs/tutorials/03_backends.ipynb index 549e4205ca..17f3c7c75d 100644 --- a/docs/tutorials/03_backends.ipynb +++ b/docs/tutorials/03_backends.ipynb @@ -79,11 +79,11 @@ { "data": { "text/plain": [ - "[,\n", - " ,\n", - " ,\n", - " ,\n", - " ]" + "[,\n", + " ,\n", + " ,\n", + " ,\n", + " ]" ] }, "execution_count": 2, @@ -112,7 +112,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 3, @@ -190,7 +190,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -250,14 +250,18 @@ { "data": { "text/plain": [ - "[,\n", + "[,\n", + " ,\n", " ,\n", + " ,\n", + " ,\n", + " ,\n", " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ]" + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ]" ] }, "execution_count": 7, @@ -266,7 +270,7 @@ } ], "source": [ - "legacy_service.backends(**program.backend_requirements)" + "legacy_service.backends(min_num_qubits=5)" ] }, { @@ -282,13 +286,271 @@ "id": "345f6414", "metadata": {}, "source": [ - "As mentioned earlier, the attributes of a backend provides information about the backend. **TODO** - finish when BackendV2 is done" + "As mentioned earlier, the attributes of [IBMBackend](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.IBMBackend.html#qiskit_ibm_runtime.IBMBackend) class provides information about the backend." ] }, { "cell_type": "code", - "execution_count": 1, - "id": "4f60899c", + "execution_count": 8, + "id": "1a0b6659", + "metadata": {}, + "outputs": [], + "source": [ + "backend = service.backend(\"ibmq_qasm_simulator\")" + ] + }, + { + "cell_type": "markdown", + "id": "f1ae6dff", + "metadata": {}, + "source": [ + "Name of the backend." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "2c7e254d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'ibmq_qasm_simulator'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "backend.name" + ] + }, + { + "cell_type": "markdown", + "id": "db124d13", + "metadata": {}, + "source": [ + "Version of the backend." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "969b2a6e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0.1.547'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "backend.backend_version" + ] + }, + { + "cell_type": "markdown", + "id": "d80ceba6", + "metadata": {}, + "source": [ + "Check if the backend is a simulator or real system." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "2f2676d9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "backend.simulator" + ] + }, + { + "cell_type": "markdown", + "id": "79cd9dd7", + "metadata": {}, + "source": [ + "Number of qubits the backend has." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "5983257b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "32" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "backend.num_qubits" + ] + }, + { + "cell_type": "markdown", + "id": "02ea81a6", + "metadata": {}, + "source": [ + "Maximum number of circuits per job." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "faff03d7", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "300" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "backend.max_circuits" + ] + }, + { + "cell_type": "markdown", + "id": "65c3f744", + "metadata": {}, + "source": [ + "A list of instructions the backend supports." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "d7c117ea", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[(Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (0,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (1,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (2,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (3,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (4,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (5,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (6,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (7,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (8,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (9,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (10,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (11,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (12,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (13,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (14,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (15,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (16,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (17,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (18,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (19,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (20,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (21,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (22,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (23,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (24,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (25,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (26,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (27,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (28,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (29,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (30,)),\n", + " (Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), (31,))]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "backend.instructions" + ] + }, + { + "cell_type": "markdown", + "id": "c91b3de3", + "metadata": {}, + "source": [ + "Coupling map of the backend." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9b219fae", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "backend.coupling_map" + ] + }, + { + "cell_type": "markdown", + "id": "06590dbc", + "metadata": {}, + "source": [ + "For a complete list of backend attributes refer to the [IBMBackend](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.IBMBackend.html#qiskit_ibm_runtime.IBMBackend) class documentation." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "f6948a08", "metadata": {}, "outputs": [ { @@ -327,7 +589,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.1" + "version": "3.9.7" } }, "nbformat": 4, diff --git a/docs/tutorials/qka.ipynb b/docs/tutorials/qka.ipynb index 07dd43e6f4..bc38daa1f5 100644 --- a/docs/tutorials/qka.ipynb +++ b/docs/tutorials/qka.ipynb @@ -484,7 +484,7 @@ " \"initial_layout\": initial_layout,\n", "}\n", "\n", - "options = {\"backend_name\": backend.name()}\n", + "options = {\"backend_name\": backend.name}\n", "\n", "job = service.run(\n", " program_id=\"quantum-kernel-alignment\",\n", diff --git a/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb b/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb index 475daab23c..e7bad35330 100644 --- a/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb +++ b/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb @@ -456,7 +456,7 @@ " pairs if return_stddev=True.\n", " \"\"\"\n", " if not isinstance(backend, str):\n", - " backend = backend.name()\n", + " backend = backend.name\n", " options = {\"backend_name\": backend}\n", "\n", " if isinstance(circuits, list) and len(circuits) != 1:\n", diff --git a/docs/tutorials/sample_vqe_program/qiskit_runtime_vqe_program.ipynb b/docs/tutorials/sample_vqe_program/qiskit_runtime_vqe_program.ipynb index fd4b0b93df..41eca54f40 100644 --- a/docs/tutorials/sample_vqe_program/qiskit_runtime_vqe_program.ipynb +++ b/docs/tutorials/sample_vqe_program/qiskit_runtime_vqe_program.ipynb @@ -416,7 +416,7 @@ "# Use the local Aer simulator\n", "from qiskit import Aer\n", "\n", - "backend = Aer.get_backend(\"qasm_simulator\")" + "backend = Aer.backend(\"qasm_simulator\")" ] }, { @@ -1121,7 +1121,7 @@ " Returns:\n", " OptimizeResult: The result in SciPy optimization format.\n", " \"\"\"\n", - " options = {\"backend_name\": backend.name()}\n", + " options = {\"backend_name\": backend.name}\n", "\n", " inputs = {}\n", "\n", diff --git a/docs/tutorials/vqe.ipynb b/docs/tutorials/vqe.ipynb index 73d38809c7..07145a723c 100644 --- a/docs/tutorials/vqe.ipynb +++ b/docs/tutorials/vqe.ipynb @@ -87,7 +87,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -330,7 +330,7 @@ "metadata": {}, "outputs": [], "source": [ - "backend_options = {\"backend_name\": backend.name()}" + "backend_options = {\"backend_name\": backend.name}" ] }, { diff --git a/program_source/qaoa/qaoa.py b/program_source/qaoa/qaoa.py index 2a5827cf1f..c85077c138 100644 --- a/program_source/qaoa/qaoa.py +++ b/program_source/qaoa/qaoa.py @@ -1929,7 +1929,7 @@ def __init__( self._coupling_map = CouplingMap(coupling_map) self._two_qubit_fidelity = {} self._max_problem_size = backend.configuration().num_qubits - self._name = backend.name() + self._name = backend.name self._use_fidelity = use_fidelity props = backend.properties() diff --git a/program_source/vqe/vqe.py b/program_source/vqe/vqe.py index ad6c61e283..5470a7228f 100644 --- a/program_source/vqe/vqe.py +++ b/program_source/vqe/vqe.py @@ -1221,7 +1221,7 @@ def main(backend, user_messenger, **kwargs): if __name__ == "__main__": # the code currently uses Aer instead of runtime provider - _backend = Aer.get_backend("qasm_simulator") + _backend = Aer.backend("qasm_simulator") user_params = {} if len(sys.argv) > 1: # If there are user parameters. diff --git a/qiskit_ibm_runtime/hub_group_project.py b/qiskit_ibm_runtime/hub_group_project.py index 0cf12e2096..06cb633b49 100644 --- a/qiskit_ibm_runtime/hub_group_project.py +++ b/qiskit_ibm_runtime/hub_group_project.py @@ -81,10 +81,7 @@ def _discover_remote_backends(self) -> Dict[str, "ibm_backend.IBMBackend"]: ) if not config: continue - backend_cls = ( - ibm_backend.IBMSimulator if config.simulator else ibm_backend.IBMBackend - ) - ret[config.backend_name] = backend_cls( + ret[config.backend_name] = ibm_backend.IBMBackend( configuration=config, api_client=self._api_client, ) diff --git a/qiskit_ibm_runtime/ibm_backend.py b/qiskit_ibm_runtime/ibm_backend.py index d801a9f156..957445d330 100644 --- a/qiskit_ibm_runtime/ibm_backend.py +++ b/qiskit_ibm_runtime/ibm_backend.py @@ -14,23 +14,35 @@ import logging -from typing import Union, Optional, Any +from typing import Iterable, Union, Optional, Any, List from datetime import datetime as python_datetime from qiskit.qobj.utils import MeasLevel, MeasReturnType -from qiskit.providers.backend import BackendV1 as Backend +from qiskit.providers.backend import BackendV2 as Backend, QubitProperties from qiskit.providers.options import Options from qiskit.providers.models import ( BackendStatus, BackendProperties, PulseDefaults, GateConfig, + QasmBackendConfiguration, + PulseBackendConfiguration, ) -from qiskit.providers.models import QasmBackendConfiguration, PulseBackendConfiguration +from qiskit.pulse.channels import ( + AcquireChannel, + ControlChannel, + DriveChannel, + MeasureChannel, +) +from qiskit.transpiler.target import Target from .api.clients import AccountClient, RuntimeClient from .api.clients.backend import BaseBackendClient from .exceptions import IBMBackendApiProtocolError +from .utils.backend_converter import ( + convert_to_target, + qubit_props_dict_from_props, +) from .utils.converters import local_to_utc from .utils.backend_decoder import ( defaults_from_server_data, @@ -59,6 +71,78 @@ class IBMBackend(Backend): status = backend.status() is_operational = status.operational jobs_in_queue = status.pending_jobs + + Here is list of attributes available on the ``IBMBackend`` class: + + * name: backend name. + * backend_version: backend version in the form X.Y.Z. + * num_qubits: number of qubits. + * target: A :class:`qiskit.transpiler.Target` object for the backend. + * basis_gates: list of basis gates names on the backend. + * gates: list of basis gates on the backend. + * local: backend is local or remote. + * simulator: backend is a simulator. + * conditional: backend supports conditional operations. + * open_pulse: backend supports open pulse. + * memory: backend supports memory. + * max_shots: maximum number of shots supported. + * coupling_map (list): The coupling map for the device + * supported_instructions (List[str]): Instructions supported by the backend. + * dynamic_reprate_enabled (bool): whether delay between programs can be set dynamically + (ie via ``rep_delay``). Defaults to False. + * rep_delay_range (List[float]): 2d list defining supported range of repetition + delays for backend in μs. First entry is lower end of the range, second entry is + higher end of the range. Optional, but will be specified when + ``dynamic_reprate_enabled=True``. + * default_rep_delay (float): Value of ``rep_delay`` if not specified by user and + ``dynamic_reprate_enabled=True``. + * 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. + * meas_kernels: Supported measurement kernels. + * discriminators: Supported discriminators. + * hamiltonian: An optional dictionary with fields characterizing the system hamiltonian. + * channel_bandwidth (list): Bandwidth of all channels + (qubit, measurement, and U) + * acquisition_latency (list): Array of dimension + n_qubits x n_registers. Latency (in units of dt) to write a + measurement result from qubit n into register slot m. + * conditional_latency (list): Array of dimension n_channels + [d->u->m] x n_registers. Latency (in units of dt) to do a + conditional operation on channel n from register slot m + * meas_map (list): Grouping of measurement which are multiplexed + * max_circuits (int): The maximum number of experiments per job + * sample_name (str): Sample name for the backend + * n_registers (int): Number of register slots available for feedback + (if conditional is True) + * register_map (list): An array of dimension n_qubits X + n_registers that specifies whether a qubit can store a + measurement in a certain register slot. + * configurable (bool): True if the backend is configurable, if the + backend is a simulator + * credits_required (bool): True if backend requires credits to run a + job. + * online_date (datetime): The date that the device went online + * display_name (str): Alternate name field for the backend + * description (str): A description for the backend + * tags (list): A list of string tags to describe the backend + * version: version of ``Backend`` class (Ex: 1, 2) + * channels: An optional dictionary containing information of each channel -- their + purpose, type, and qubits operated on. + * parametric_pulses (list): A list of pulse shapes which are supported on the backend. + For example: ``['gaussian', 'constant']`` + * processor_type (dict): Processor type for this backend. A dictionary of the + form ``{"family": , "revision": , segment: }`` such as + ``{"family": "Canary", "revision": "1.0", segment: "A"}``. + + * family: Processor family of this backend. + * revision: Revision version of this processor. + * segment: Segment this processor belongs to within a larger chip. """ id_warning_issued = False @@ -74,13 +158,80 @@ def __init__( configuration: Backend configuration. api_client: IBM Quantum client used to communicate with the server. """ - super().__init__(configuration=configuration) - + super().__init__( + name=configuration.backend_name, + online_date=configuration.online_date, + backend_version=configuration.backend_version, + ) self._api_client = api_client - - # Attributes used by caching functions. + self._configuration = configuration self._properties = None + self._qubit_properties = None self._defaults = None + self._target = None + self._max_circuits = configuration.max_experiments + if not self._configuration.simulator: + self.options.set_validator("noise_model", type(None)) + self.options.set_validator("seed_simulator", type(None)) + if hasattr(configuration, "max_shots"): + self.options.set_validator("shots", (1, configuration.max_shots)) + if hasattr(configuration, "rep_delay_range"): + self.options.set_validator( + "rep_delay", + (configuration.rep_delay_range[0], configuration.rep_delay_range[1]), + ) + + def __getattr__(self, name: str) -> Any: + """Gets attribute from self or configuration + + This magic method executes when user accesses an attribute that + does not yet exist on IBMBackend class. + """ + # Lazy load properties and pulse defaults and construct the target object. + self._get_properties() + self._get_defaults() + self._convert_to_target() + # Check if the attribute now is available on IBMBackend class due to above steps + try: + return super().__getattribute__(name) + except AttributeError: + pass + # If attribute is still not available on IBMBackend class, + # fallback to check if the attribute is available in configuration + try: + return self._configuration.__getattribute__(name) + except AttributeError: + raise AttributeError( + "'{}' object has no attribute '{}'".format( + self.__class__.__name__, name + ) + ) + + def _get_properties(self) -> None: + """Gets backend properties and decodes it""" + if not self._properties: + api_properties = self._api_client.backend_properties(self.name) + if api_properties: + backend_properties = properties_from_server_data(api_properties) + self._properties = backend_properties + + def _get_defaults(self) -> None: + """Gets defaults if pulse backend and decodes it""" + if not self._defaults and isinstance( + self._configuration, PulseBackendConfiguration + ): + api_defaults = self._api_client.backend_pulse_defaults(self.name) + if api_defaults: + self._defaults = defaults_from_server_data(api_defaults) + + def _convert_to_target(self) -> None: + """Converts backend configuration, properties and defaults to Target object""" + if not self._target: + self._target = convert_to_target( + configuration=self._configuration, + properties=self._properties, + defaults=self._defaults, + ) @classmethod def _default_options(cls) -> Options: @@ -99,8 +250,74 @@ def _default_options(cls) -> Options: rep_delay=None, init_qubits=True, use_measure_esp=None, + # Simulator only + noise_model=None, + seed_simulator=None, ) + @property + def dtm(self) -> float: + """Return the system time resolution of output signals + + Returns: + dtm: The output signal timestep in seconds. + """ + return self._configuration.dtm + + @property + def max_circuits(self) -> int: + """The maximum number of circuits + + The maximum number of circuits (or Pulse schedules) that can be + run in a single job. If there is no limit this will return None. + """ + return self._max_circuits + + @property + def meas_map(self) -> List[List[int]]: + """Return the grouping of measurements which are multiplexed + + This is required to be implemented if the backend supports Pulse + scheduling. + + Returns: + meas_map: The grouping of measurements which are multiplexed + """ + return self._configuration.meas_map + + @property + def target(self) -> Target: + """A :class:`qiskit.transpiler.Target` object for the backend. + + Returns: + Target + """ + self._get_properties() + self._get_defaults() + self._convert_to_target() + return self._target + + def qubit_properties( + self, qubit: Union[int, List[int]] + ) -> Union[QubitProperties, List[QubitProperties]]: + """Return QubitProperties for a given qubit. + + Args: + qubit: The qubit to get the + :class:`~qiskit.provider.QubitProperties` object for. This can + be a single integer for 1 qubit or a list of qubits and a list + of :class:`~qiskit.provider.QubitProperties` objects will be + returned in the same order + """ + self._get_properties() + if not self._qubit_properties: + self._qubit_properties = qubit_props_dict_from_props(self._properties) + if isinstance(qubit, int): # type: ignore[unreachable] + return self._qubit_properties.get(qubit) + if isinstance(qubit, List): + return [self._qubit_properties.get(q) for q in qubit] + return None + def properties( self, refresh: bool = False, datetime: Optional[python_datetime] = None ) -> Optional[BackendProperties]: @@ -131,12 +348,14 @@ def properties( NotImplementedError: If `datetime` is specified when cloud rutime is used. """ # pylint: disable=arguments-differ + if self._configuration.simulator: + # Simulators do not have backend properties. + return None if not isinstance(refresh, bool): raise TypeError( "The 'refresh' argument needs to be a boolean. " "{} is of type {}".format(refresh, type(refresh)) ) - if datetime: if not isinstance(datetime, python_datetime): raise TypeError("'{}' is not of type 'datetime'.") @@ -145,10 +364,9 @@ def properties( "'datetime' is not supported by cloud runtime." ) datetime = local_to_utc(datetime) - if datetime or refresh or self._properties is None: api_properties = self._api_client.backend_properties( - self.name(), datetime=datetime + self.name, datetime=datetime ) if not api_properties: return None @@ -172,7 +390,7 @@ def status(self) -> BackendStatus: Raises: IBMBackendApiProtocolError: If the status for the backend cannot be formatted properly. """ - api_status = self._api_client.backend_status(self.name()) + api_status = self._api_client.backend_status(self.name) try: return BackendStatus.from_dict(api_status) @@ -197,7 +415,7 @@ def defaults(self, refresh: bool = False) -> Optional[PulseDefaults]: The backend pulse defaults or ``None`` if the backend does not support pulse. """ if refresh or self._defaults is None: - api_defaults = self._api_client.backend_pulse_defaults(self.name()) + api_defaults = self._api_client.backend_pulse_defaults(self.name) if api_defaults: self._defaults = defaults_from_server_data(api_defaults) else: @@ -222,8 +440,47 @@ def configuration( """ return self._configuration + def drive_channel(self, qubit: int) -> DriveChannel: + """Return the drive channel for the given qubit. + + Returns: + DriveChannel: The Qubit drive channel + """ + return self._configuration.drive(qubit=qubit) + + def measure_channel(self, qubit: int) -> MeasureChannel: + """Return the measure stimulus channel for the given qubit. + + Returns: + MeasureChannel: The Qubit measurement stimulus line + """ + return self._configuration.measure(qubit=qubit) + + def acquire_channel(self, qubit: int) -> AcquireChannel: + """Return the acquisition channel for the given qubit. + + Returns: + AcquireChannel: The Qubit measurement acquisition line. + """ + return self._configuration.acquire(qubit=qubit) + + def control_channel(self, qubits: Iterable[int]) -> List[ControlChannel]: + """Return the secondary drive channel for the given qubit + + This is typically utilized for controlling multiqubit interactions. + This channel is derived from other channels. + + Args: + qubits: Tuple or list of qubits of the form + ``(control_qubit, target_qubit)``. + + Returns: + List[ControlChannel]: The Qubit measurement acquisition line. + """ + return self._configuration.control(qubits=qubits) + def __repr__(self) -> str: - return "<{}('{}')>".format(self.__class__.__name__, self.name()) + return "<{}('{}')>".format(self.__class__.__name__, self.name) def run(self, *args: Any, **kwargs: Any) -> None: """Not supported method""" @@ -233,23 +490,6 @@ def run(self, *args: Any, **kwargs: Any) -> None: ) -class IBMSimulator(IBMBackend): - """Backend class interfacing with an IBM Quantum simulator.""" - - @classmethod - def _default_options(cls) -> Options: - """Default runtime options.""" - options = super()._default_options() - options.update_options(noise_model=None, seed_simulator=None) - return options - - def properties( - self, refresh: bool = False, datetime: Optional[python_datetime] = None - ) -> None: - """Return ``None``, simulators do not have backend properties.""" - return None - - class IBMRetiredBackend(IBMBackend): """Backend class interfacing with an IBM Quantum device no longer available.""" @@ -266,7 +506,7 @@ def __init__( """ super().__init__(configuration, api_client) self._status = BackendStatus( - backend_name=self.name(), + backend_name=self.name, backend_version=self.configuration().backend_version, operational=False, pending_jobs=0, @@ -276,7 +516,7 @@ def __init__( @classmethod def _default_options(cls) -> Options: """Default runtime options.""" - return Options() + return Options(shots=4000) def properties( self, refresh: bool = False, datetime: Optional[python_datetime] = None @@ -302,6 +542,7 @@ def from_name( configuration = QasmBackendConfiguration( backend_name=backend_name, backend_version="0.0.0", + online_date="2019-10-16T04:00:00Z", n_qubits=1, basis_gates=[], simulator=False, @@ -312,5 +553,6 @@ def from_name( max_shots=1, gates=[GateConfig(name="TODO", parameters=[], qasm_def="TODO")], coupling_map=[[0, 1]], + max_experiments=300, ) return cls(configuration, api) diff --git a/qiskit_ibm_runtime/ibm_runtime_service.py b/qiskit_ibm_runtime/ibm_runtime_service.py index 80beb5930a..695111efa5 100644 --- a/qiskit_ibm_runtime/ibm_runtime_service.py +++ b/qiskit_ibm_runtime/ibm_runtime_service.py @@ -285,14 +285,10 @@ def _discover_cloud_backends(self) -> Dict[str, "ibm_backend.IBMBackend"]: ) if not config: continue - backend_cls = ( - ibm_backend.IBMSimulator if config.simulator else ibm_backend.IBMBackend - ) - ret[config.backend_name] = backend_cls( + ret[config.backend_name] = ibm_backend.IBMBackend( configuration=config, api_client=self._api_client, ) - return ret def _resolve_crn(self, account: Account) -> None: @@ -462,7 +458,7 @@ def _get_hgp( def _discover_backends(self) -> None: """Discovers the remote backends for this account, if not already known.""" for backend in self._backends.values(): - backend_name = to_python_identifier(backend.name()) + backend_name = to_python_identifier(backend.name) # Append _ if duplicate while backend_name in self.__dict__: backend_name += "_" diff --git a/qiskit_ibm_runtime/jupyter/backend_info.py b/qiskit_ibm_runtime/jupyter/backend_info.py index dbabd2564b..1340895b79 100644 --- a/qiskit_ibm_runtime/jupyter/backend_info.py +++ b/qiskit_ibm_runtime/jupyter/backend_info.py @@ -43,7 +43,7 @@ def backend_widget(backend: Union[IBMBackend, FakeBackend]) -> None: vue.ToolbarTitle( children=[ "{} @ ({}/{}/{})".format( - backend.name(), cred.hub, cred.group, cred.project + backend.name, cred.hub, cred.group, cred.project ) ], style_="color:white", diff --git a/qiskit_ibm_runtime/jupyter/dashboard/backend_widget.py b/qiskit_ibm_runtime/jupyter/dashboard/backend_widget.py index 35a63fd4b7..3d4c0c1481 100644 --- a/qiskit_ibm_runtime/jupyter/dashboard/backend_widget.py +++ b/qiskit_ibm_runtime/jupyter/dashboard/backend_widget.py @@ -48,7 +48,7 @@ def make_backend_widget(backend_item: BackendWithProviders) -> wid.HBox: next_resrv = get_next_reservation(backend) name_str = "%s" - backend_name = wid.HTML(value=name_str % backend.name()) + backend_name = wid.HTML(value=name_str % backend.name) qubits_wid = wid.HTML(value=STAT_FONT_TITLE.format("Qubits:")) qubits_val_wid = wid.HTML(value=STAT_FONT_VALUE.format(config.n_qubits)) diff --git a/qiskit_ibm_runtime/jupyter/dashboard/dashboard.py b/qiskit_ibm_runtime/jupyter/dashboard/dashboard.py index 26728fdc78..44aab7b35f 100644 --- a/qiskit_ibm_runtime/jupyter/dashboard/dashboard.py +++ b/qiskit_ibm_runtime/jupyter/dashboard/dashboard.py @@ -94,12 +94,12 @@ def _get_backends(self) -> None: ) for back in pro.backends(): if not back.configuration().simulator: - if back.name() not in ibm_backends.keys(): - ibm_backends[back.name()] = BackendWithProviders( + if back.name not in ibm_backends.keys(): + ibm_backends[back.name] = BackendWithProviders( backend=back, providers=[pro_name] ) else: - ibm_backends[back.name()].providers.append(pro_name) + ibm_backends[back.name].providers.append(pro_name) self.backend_dict = ibm_backends diff --git a/qiskit_ibm_runtime/utils/backend_converter.py b/qiskit_ibm_runtime/utils/backend_converter.py new file mode 100644 index 0000000000..0669b850c8 --- /dev/null +++ b/qiskit_ibm_runtime/utils/backend_converter.py @@ -0,0 +1,142 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Converters for migration from IBM Quantum BackendV1 to BackendV2.""" + +from typing import Any, Dict + +from qiskit.transpiler.target import Target, InstructionProperties +from qiskit.providers.backend import QubitProperties +from qiskit.utils.units import apply_prefix +from qiskit.circuit.library.standard_gates import IGate, SXGate, XGate, CXGate, RZGate +from qiskit.circuit.parameter import Parameter +from qiskit.circuit.gate import Gate +from qiskit.circuit.measure import Measure +from qiskit.circuit.reset import Reset +from qiskit.providers.models import ( + BackendConfiguration, + BackendProperties, + PulseDefaults, +) + + +def convert_to_target( + configuration: BackendConfiguration, + properties: BackendProperties = None, + defaults: PulseDefaults = None, +) -> Target: + """Uses configuration, properties and pulse defaults + to construct and return Target class. + """ + name_mapping = { + "id": IGate(), + "sx": SXGate(), + "x": XGate(), + "cx": CXGate(), + "rz": RZGate(Parameter("λ")), + "reset": Reset(), + } + custom_gates = {} + target = Target(num_qubits=configuration.n_qubits) + # Parse from properties if it exsits + if properties is not None: + # Parse instructions + gates: Dict[str, Any] = {} + for gate in properties.gates: + name = gate.gate + if name in name_mapping: + if name not in gates: + gates[name] = {} + elif name not in custom_gates: + custom_gate = Gate(name, len(gate.qubits), []) + custom_gates[name] = custom_gate + gates[name] = {} + + qubits = tuple(gate.qubits) + gate_props = {} + for param in gate.parameters: + if param.name == "gate_error": + gate_props["error"] = param.value + if param.name == "gate_length": + gate_props["duration"] = apply_prefix(param.value, param.unit) + gates[name][qubits] = InstructionProperties(**gate_props) + for gate, props in gates.items(): + if gate in name_mapping: + inst = name_mapping.get(gate) + else: + inst = custom_gates[gate] + target.add_instruction(inst, props) + # Create measurement instructions: + measure_props = {} + for qubit, _ in enumerate(properties.qubits): + measure_props[(qubit,)] = InstructionProperties( + duration=properties.readout_length(qubit), + error=properties.readout_error(qubit), + ) + target.add_instruction(Measure(), measure_props) + # Parse from configuration because properties doesn't exist + else: + for gate in configuration.gates: + name = gate.name + gate_props = ( + {tuple(x): None for x in gate.coupling_map} # type: ignore[misc] + if hasattr(gate, "coupling_map") + else {None: None} + ) + gate_len = len(gate.coupling_map[0]) if hasattr(gate, "coupling_map") else 0 + if name in name_mapping: + target.add_instruction(name_mapping[name], gate_props) + else: + custom_gate = Gate(name, gate_len, []) + target.add_instruction(custom_gate, gate_props) + target.add_instruction(Measure()) + # parse global configuration properties + if hasattr(configuration, "dt"): + target.dt = configuration.dt + if hasattr(configuration, "timing_constraints"): + target.granularity = configuration.timing_constraints.get("granularity") + target.min_length = configuration.timing_constraints.get("min_length") + target.pulse_alignment = configuration.timing_constraints.get("pulse_alignment") + target.aquire_alignment = configuration.timing_constraints.get( + "acquire_alignment" + ) + # If pulse defaults exists use that as the source of truth + if defaults is not None: + inst_map = defaults.instruction_schedule_map + for inst in inst_map.instructions: + for qarg in inst_map.qubits_with_instruction(inst): + sched = inst_map.get(inst, qarg) + if inst in target: + try: + qarg = tuple(qarg) + except TypeError: + qarg = (qarg,) + if inst == "measure": + for qubit in qarg: + target[inst][(qubit,)].calibration = sched + else: + target[inst][qarg].calibration = sched + return target + + +def qubit_props_dict_from_props(properties: BackendProperties) -> QubitProperties: + """Uses BackendProperties to construct + and return QubitProperties class. + """ + qubit_props = {} + for qubit, _ in enumerate(properties.qubits): + qubit_props[qubit] = QubitProperties( + t1=properties.t1(qubit), + t2=properties.t2(qubit), + frequency=properties.frequency(qubit), + ) + return qubit_props diff --git a/qiskit_ibm_runtime/utils/backend_decoder.py b/qiskit_ibm_runtime/utils/backend_decoder.py index 800b440f43..5cc38e3b5d 100644 --- a/qiskit_ibm_runtime/utils/backend_decoder.py +++ b/qiskit_ibm_runtime/utils/backend_decoder.py @@ -20,8 +20,6 @@ from qiskit.providers.models import ( BackendProperties, PulseDefaults, -) -from qiskit.providers.models import ( PulseBackendConfiguration, QasmBackendConfiguration, ) diff --git a/qiskit_ibm_runtime/visualization/interactive/error_map.py b/qiskit_ibm_runtime/visualization/interactive/error_map.py index 22e4e1cb85..f039dafae0 100644 --- a/qiskit_ibm_runtime/visualization/interactive/error_map.py +++ b/qiskit_ibm_runtime/visualization/interactive/error_map.py @@ -518,7 +518,7 @@ def iplot_error_map( for ann in fig["layout"]["annotations"]: ann["font"] = dict(size=13) - title_text = "{} Error Map".format(backend.name()) if show_title else "" + title_text = "{} Error Map".format(backend.name) if show_title else "" fig.update_layout( showlegend=False, plot_bgcolor=background_color, diff --git a/releasenotes/archive/0.13/runtime-f9a57a8286fa6197.yaml b/releasenotes/archive/0.13/runtime-f9a57a8286fa6197.yaml index 266bd065c4..029bc9b6e5 100644 --- a/releasenotes/archive/0.13/runtime-f9a57a8286fa6197.yaml +++ b/releasenotes/archive/0.13/runtime-f9a57a8286fa6197.yaml @@ -36,7 +36,7 @@ features: # Prepare the inputs. See program documentation on input parameters. inputs = {...} - options = {"backend_name": provider.backend.ibmq_montreal.name()} + options = {"backend_name": provider.backend.ibmq_montreal.name} job = provider.runtime.run(program_id="circuit-runner", options=options, diff --git a/requirements.txt b/requirements.txt index 1384881d93..34a1194d53 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -qiskit-terra>=0.18.0 +qiskit-terra>=0.19.2 requests>=2.19 requests_ntlm>=1.1.0 numpy>=1.13 diff --git a/setup.py b/setup.py index e528087a75..f5d2980891 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ import setuptools REQUIREMENTS = [ - "qiskit-terra>=0.18.0", + "qiskit-terra>=0.19.2", "requests>=2.19", "requests-ntlm>=1.1.0", "numpy>=1.13", diff --git a/test/ibm_test_case.py b/test/ibm_test_case.py index e8bc93bff9..9b04238a35 100644 --- a/test/ibm_test_case.py +++ b/test/ibm_test_case.py @@ -161,7 +161,7 @@ def _find_sim_backends(cls): """Find a simulator backend for each service.""" cls.sim_backends[cls.service.auth] = cls.service.backends(simulator=True)[ 0 - ].name() + ].name def _run_program( self, diff --git a/test/integration/test_backend.py b/test/integration/test_backend.py index 500d99473b..86d039272c 100644 --- a/test/integration/test_backend.py +++ b/test/integration/test_backend.py @@ -14,6 +14,7 @@ from unittest import SkipTest +from qiskit.transpiler.target import Target from ..ibm_test_case import IBMIntegrationTestCase from ..decorators import run_integration_test @@ -26,7 +27,7 @@ def test_backends(self, service): """Test getting all backends.""" backends = service.backends() self.assertTrue(backends) - backend_names = [back.name() for back in backends] + backend_names = [back.name for back in backends] self.assertEqual( len(backend_names), len(set(backend_names)), @@ -37,7 +38,7 @@ def test_backends(self, service): def test_get_backend(self, service): """Test getting a backend.""" backends = service.backends() - backend = service.backend(backends[0].name()) + backend = service.backend(backends[0].name) self.assertTrue(backend) @@ -58,16 +59,36 @@ def setUpClass(cls): simulator=False, min_num_qubits=5, instance=cls.dependencies.instance ) + def test_backend_target(self): + """Check if the target property is set.""" + backend = self.backend + with self.subTest(backend=backend.name): + self.assertIsNotNone(backend.target) + self.assertIsInstance(backend.target, Target) + + def test_backend_max_circuits(self): + """Check if the max_circuits property is set.""" + backend = self.backend + with self.subTest(backend=backend.name): + self.assertIsNotNone(backend.max_circuits) + + def test_backend_simulator(self): + """Test if a configuration attribute (ex: simulator) is available as backend attribute.""" + backend = self.backend + with self.subTest(backend=backend.name): + self.assertIsNotNone(backend.simulator) + self.assertEqual(backend.simulator, backend.configuration().simulator) + def test_backend_status(self): """Check the status of a real chip.""" backend = self.backend - with self.subTest(backend=backend.name()): + with self.subTest(backend=backend.name): self.assertTrue(backend.status().operational) def test_backend_properties(self): """Check the properties of calibration of a real chip.""" backend = self.backend - with self.subTest(backend=backend.name()): + with self.subTest(backend=backend.name): if backend.configuration().simulator: raise SkipTest("Skip since simulator does not have properties.") self.assertIsNotNone(backend.properties()) @@ -75,7 +96,7 @@ def test_backend_properties(self): def test_backend_pulse_defaults(self): """Check the backend pulse defaults of each backend.""" backend = self.backend - with self.subTest(backend=backend.name()): + with self.subTest(backend=backend.name): if backend.configuration().simulator: raise SkipTest("Skip since simulator does not have defaults.") if not backend.configuration().open_pulse: @@ -85,12 +106,19 @@ def test_backend_pulse_defaults(self): def test_backend_configuration(self): """Check the backend configuration of each backend.""" backend = self.backend - with self.subTest(backend=backend.name()): + with self.subTest(backend=backend.name): self.assertIsNotNone(backend.configuration()) + def test_backend_invalid_attribute(self): + """Check if AttributeError is raised when an invalid backend attribute is accessed.""" + backend = self.backend + with self.subTest(backend=backend.name): + with self.assertRaises(AttributeError): + backend.foobar # pylint: disable=pointless-statement + def test_backend_run(self): """Check one cannot do backend.run""" backend = self.backend - with self.subTest(backend=backend.name()): + with self.subTest(backend=backend.name): with self.assertRaises(RuntimeError): backend.run() diff --git a/test/integration/test_job.py b/test/integration/test_job.py index 0cff25b70f..07671e340b 100644 --- a/test/integration/test_job.py +++ b/test/integration/test_job.py @@ -205,7 +205,7 @@ def test_job_inputs(self, service): def test_job_backend(self, service): """Test job backend.""" job = self._run_program(service) - self.assertEqual(self.sim_backends[service.auth], job.backend.name()) + self.assertEqual(self.sim_backends[service.auth], job.backend.name) @run_integration_test def test_job_program_id(self, service): diff --git a/test/unit/test_backend_retrieval.py b/test/unit/test_backend_retrieval.py index 856ef47cdc..628be6a563 100644 --- a/test/unit/test_backend_retrieval.py +++ b/test/unit/test_backend_retrieval.py @@ -28,7 +28,7 @@ class TestBackendFilters(IBMTestCase): def test_no_filter(self, service): """Test no filtering.""" # FakeRuntimeService by default creates 3 backends. - backend_name = [back.name() for back in service.backends()] + backend_name = [back.name for back in service.backends()] self.assertEqual(len(backend_name), 3) @run_legacy_and_cloud_fake @@ -39,7 +39,7 @@ def test_filter_by_name(self, service): FakeRuntimeService.DEFAULT_UNIQUE_BACKEND_PREFIX + "0", ]: with self.subTest(name=name): - backend_name = [back.name() for back in service.backends(name=name)] + backend_name = [back.name for back in service.backends(name=name)] self.assertEqual(len(backend_name), 1) def test_filter_by_instance_legacy(self): @@ -48,7 +48,7 @@ def test_filter_by_instance_legacy(self): for hgp in FakeRuntimeService.DEFAULT_HGPS: with self.subTest(hgp=hgp): backends = service.backends(instance=hgp) - backend_name = [back.name() for back in backends] + backend_name = [back.name for back in backends] self.assertEqual(len(backend_name), 2) for back in backends: self.assertEqual(back._api_client.hgp, hgp) @@ -128,7 +128,7 @@ def test_filter_least_busy(self): for service in services: with self.subTest(service=service.auth): backend = service.least_busy() - self.assertEqual(backend.name(), "bingo") + self.assertEqual(backend.name, "bingo") def test_filter_min_num_qubits(self): """Test filtering by minimum number of qubits.""" diff --git a/test/unit/test_jobs.py b/test/unit/test_jobs.py index 9eeaf8912a..aeb3002bc1 100644 --- a/test/unit/test_jobs.py +++ b/test/unit/test_jobs.py @@ -92,7 +92,7 @@ def test_run_program_default_hgp_backend(self): default_hgp = list(service._hgps.values())[0] self.assertIn(backend, default_hgp.backends.keys()) job = run_program(service=service, backend_name=backend) - self.assertEqual(job.backend.name(), backend) + self.assertEqual(job.backend.name, backend) self.assertEqual( job.backend._api_client.hgp, FakeRuntimeService.DEFAULT_HGPS[0] ) @@ -104,7 +104,7 @@ def test_run_program_non_default_hgp_backend(self): default_hgp = list(service._hgps.values())[0] self.assertNotIn(backend, default_hgp.backends.keys()) job = run_program(service=service, backend_name=backend) - self.assertEqual(job.backend.name(), backend) + self.assertEqual(job.backend.name, backend) def test_run_program_by_hgp_backend(self): """Test running a program with both backend and hgp.""" @@ -114,7 +114,7 @@ def test_run_program_by_hgp_backend(self): job = run_program( service=service, backend_name=backend, instance=non_default_hgp ) - self.assertEqual(job.backend.name(), backend) + self.assertEqual(job.backend.name, backend) self.assertEqual(job.backend._api_client.hgp, non_default_hgp) def test_run_program_by_hgp_bad_backend(self): diff --git a/test/utils.py b/test/utils.py index 7fae9311b2..6ff8431637 100644 --- a/test/utils.py +++ b/test/utils.py @@ -134,8 +134,8 @@ def get_real_device(service): try: # TODO: Remove filters when ibmq_berlin is removed return service.least_busy( - simulator=False, filters=lambda b: b.name() != "ibmq_berlin" - ).name() + simulator=False, filters=lambda b: b.name != "ibmq_berlin" + ).name except QiskitBackendNotFoundError: raise unittest.SkipTest("No real device") # cloud has no real device