Source code for qiskit_ibm_provider.ibm_backend

# This code is part of Qiskit.
# (C) Copyright IBM 2021.
# 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
# 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.

"""Module for interfacing with an IBM Quantum Backend."""

import copy
import logging
import warnings
from dataclasses import asdict
from datetime import datetime as python_datetime
from typing import Iterable, Dict, List, Union, Optional, Any

from qiskit.circuit import QuantumCircuit
from qiskit.providers.backend import BackendV2 as Backend
from qiskit.providers.models import (
from qiskit.providers.options import Options
from qiskit.pulse.channels import (

from qiskit.qobj.utils import MeasLevel, MeasReturnType
from import Publisher
from qiskit.transpiler.passmanager import PassManager
from import Target

from qiskit_ibm_provider import (  # pylint: disable=unused-import
from .session import Session
from .api.clients import AccountClient
from .exceptions import (

from .job import IBMJob, IBMCircuitJob
from .transpiler.passes.basis.convert_id_to_delay import (
from .utils import validate_job_tags, are_circuits_dynamic
from .utils.options import QASM2Options, QASM3Options
from .utils.converters import local_to_utc
from .utils.json_decoder import (
from .api.exceptions import RequestsApiError

logger = logging.getLogger(__name__)

QOBJRUNNERPROGRAMID = "circuit-runner"

[docs]class IBMBackend(Backend): """Backend class interfacing with an IBM Quantum device. You can run experiments on a backend using the :meth:`run()` method. The :meth:`run()` method takes one or more :class:`~qiskit.circuit.QuantumCircuit` and returns an :class:`~qiskit_ibm_provider.job.IBMJob` instance that represents the submitted job. Each job has a unique job ID, which can later be used to retrieve the job. An example of this flow:: from qiskit import transpile from qiskit_ibm_provider import IBMProvider from qiskit.circuit.random import random_circuit provider = IBMProvider() backend = provider.backend.ibmq_vigo qx = random_circuit(n_qubits=5, depth=4) transpiled = transpile(qx, backend=backend) job = retrieved_job = provider.backend.retrieve_job(job.job_id()) Note: * Unlike :meth:`qiskit.execute`, the :meth:`run` method does not transpile the circuits for you, so be sure to do so before submitting them. * You should not instantiate the ``IBMBackend`` class directly. Instead, use the methods provided by an :class:`IBMProvider` instance to retrieve and handle backends. Other methods return information about the backend. For example, the :meth:`status()` method returns a :class:`BackendStatus<qiskit.providers.models.BackendStatus>` instance. The instance contains the ``operational`` and ``pending_jobs`` attributes, which state whether the backend is operational and also the number of jobs in the server queue for the backend, respectively:: 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": <str>, "revision": <str>, segment: <str>}`` 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 def __init__( self, configuration: Union[QasmBackendConfiguration, PulseBackendConfiguration], provider: "ibm_provider.IBMProvider", api_client: AccountClient, instance: Optional[str] = None, ) -> None: """IBMBackend constructor. Args: configuration: Backend configuration. provider: IBM Quantum account provider. api_client: IBM Quantum client used to communicate with the server. """ super().__init__( provider=provider, name=configuration.backend_name, online_date=configuration.online_date, backend_version=configuration.backend_version, ) self._instance = instance self._api_client = api_client self._configuration = configuration self._properties = None self._defaults = None self._target = None self._max_circuits = configuration.max_experiments self._session: Session = None 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. """ # Prevent recursion since these properties are accessed within __getattr__ if name in ["_properties", "_defaults", "_target", "_configuration"]: raise AttributeError( "'{}' object has no attribute '{}'".format( self.__class__.__name__, name ) ) 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_target( self, *, datetime: Optional[python_datetime] = None, refresh: bool = False, ) -> Target: """Gets target from configuration, properties and pulse defaults.""" if datetime: if not isinstance(datetime, python_datetime): raise TypeError("'{}' is not of type 'datetime'.") datetime = local_to_utc(datetime) if datetime or refresh or self._target is None: client = getattr(self.provider, "_runtime_client") api_properties = client.backend_properties(, datetime=datetime) api_pulse_defaults = client.backend_pulse_defaults( target = target_from_server_data( configuration=self._configuration, pulse_defaults=api_pulse_defaults, properties=api_properties, ) if datetime: # Don't cache result. return target self._target = target return self._target @classmethod def _default_options(cls) -> Options: """Default runtime options.""" return Options(**{**asdict(QASM3Options()), **asdict(QASM2Options())}) @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 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 """ return self._get_target()
[docs] def target_history(self, datetime: Optional[python_datetime] = None) -> Target: """A :class:`qiskit.transpiler.Target` object for the backend. Returns: Target with properties found on `datetime` """ return self._get_target(datetime=datetime)
[docs] def run( self, circuits: Union[QuantumCircuit, str, List[Union[QuantumCircuit, str]]], dynamic: bool = None, job_tags: Optional[List[str]] = None, init_circuit: Optional[QuantumCircuit] = None, init_num_resets: Optional[int] = None, header: Optional[Dict] = None, shots: Optional[Union[int, float]] = None, memory: Optional[bool] = None, meas_level: Optional[Union[int, MeasLevel]] = None, meas_return: Optional[Union[str, MeasReturnType]] = None, rep_delay: Optional[float] = None, init_qubits: Optional[bool] = None, use_measure_esp: Optional[bool] = None, noise_model: Optional[Any] = None, seed_simulator: Optional[int] = None, **run_config: Dict, ) -> IBMJob: """Run on the backend. If a keyword specified here is also present in the ``options`` attribute/object, the value specified here will be used for this run. Args: circuits: An individual or a list of :class:`~qiskit.circuits.QuantumCircuit`. 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. init_circuit: A quantum circuit to execute for initializing qubits before each circuit. If specified, ``init_num_resets`` is ignored. Applicable only if ``dynamic=True`` is specified. init_num_resets: The number of qubit resets to insert before each circuit execution. The following parameters are applicable only if ``dynamic=False`` is specified or defaulted to. header: User input that will be attached to the job and will be copied to the corresponding result header. Headers do not affect the run. This replaces the old ``Qobj`` header. shots: Number of repetitions of each circuit, for sampling. Default: 4000 or ``max_shots`` from the backend configuration, whichever is smaller. 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) * ``2`` (default), a discriminator is selected and the qubit state is stored (0 or 1) meas_return: Level of measurement data for the backend to return. For ``meas_level`` 0 and 1: * ``single`` returns information from every shot. * ``avg`` returns average measurement output (averaged over number of shots). rep_delay: Delay between programs in seconds. Only supported on certain backends (if ``backend.configuration().dynamic_reprate_enabled=True``). If supported, ``rep_delay`` must be from the range supplied by the backend (``backend.configuration().rep_delay_range``). Default is given by ``backend.configuration().default_rep_delay``. init_qubits: Whether to reset the qubits to the ground state for each shot. Default: ``True``. use_measure_esp: Whether to use excited state promoted (ESP) readout for measurements which are the terminal instruction to a qubit. ESP readout can offer higher fidelity than standard measurement sequences. See `here <>`_. Default: ``True`` if backend supports ESP readout, else ``False``. Backend support for ESP readout is determined by the flag ``measure_esp_enabled`` in ``backend.configuration()``. noise_model: Noise model. (Simulators only) seed_simulator: Random seed to control sampling. (Simulators only) **run_config: Extra arguments used to configure the run. Returns: The job to be executed. Raises: IBMBackendApiError: If an unexpected error occurred while submitting the job. IBMBackendApiProtocolError: If an unexpected value received from the server. IBMBackendValueError: - If an input parameter value is not valid. - If ESP readout is used and the backend does not support this. """ # pylint: disable=arguments-differ validate_job_tags(job_tags, IBMBackendValueError) if not isinstance(circuits, List): circuits = [circuits] self._check_circuits_attributes(circuits) if ( use_measure_esp and getattr(self.configuration(), "measure_esp_enabled", False) is False ): raise IBMBackendValueError( "ESP readout not supported on this device. Please make sure the flag " "'use_measure_esp' is unset or set to 'False'." ) actually_dynamic = are_circuits_dynamic(circuits) if dynamic is False and actually_dynamic: warnings.warn( "Parameter 'dynamic' is False, but the circuit contains dynamic constructs." ) dynamic = dynamic or actually_dynamic if dynamic and "qasm3" not in getattr( self.configuration(), "supported_features", [] ): warnings.warn(f"The backend {} does not support dynamic circuits.") status = self.status() if status.operational is True and status.status_msg != "active": warnings.warn(f"The backend {} is currently paused.") program_id = str(run_config.get("program_id", "")) if not program_id: if dynamic: program_id = QASM3RUNNERPROGRAMID else: program_id = QOBJRUNNERPROGRAMID else: run_config.pop("program_id", None) image: Optional[str] = run_config.get("image", None) # type: ignore if image is not None: image = str(image) if isinstance(init_circuit, bool): warnings.warn( "init_circuit does not accept boolean values. " "A quantum circuit should be passed in instead." ) if isinstance(shots, float): shots = int(shots) if not self.configuration().simulator: circuits = self._deprecate_id_instruction(circuits) run_config_dict = self._get_run_config( program_id=program_id, init_circuit=init_circuit, init_num_resets=init_num_resets, header=header, shots=shots, memory=memory, meas_level=meas_level, meas_return=meas_return, rep_delay=rep_delay, init_qubits=init_qubits, use_measure_esp=use_measure_esp, noise_model=noise_model, seed_simulator=seed_simulator, **run_config, ) run_config_dict["circuits"] = circuits if not program_id.startswith(QASM3RUNNERPROGRAMID): # Transpiling in circuit-runner is deprecated. run_config_dict["skip_transpilation"] = True return self._runtime_run( program_id=program_id, inputs=run_config_dict,, job_tags=job_tags, image=image, )
def _runtime_run( self, program_id: str, inputs: Dict, backend_name: str, job_tags: Optional[List[str]] = None, image: Optional[str] = None, ) -> IBMCircuitJob: """Runs the runtime program and returns the corresponding job object""" hgp_name = self._instance or self.provider._get_hgp().name session = self._session if session: if not raise RuntimeError(f"The session {session.session_id} is closed.") session_id = session.session_id max_execution_time = session._max_time start_session = session_id is None else: session_id = None max_execution_time = None start_session = False try: response = self.provider._runtime_client.program_run( program_id=program_id, backend_name=backend_name, params=inputs, hgp=hgp_name, job_tags=job_tags, session_id=session_id, start_session=start_session, max_execution_time=max_execution_time, image=image, ) except RequestsApiError as ex: raise IBMBackendApiError("Error submitting job: {}".format(str(ex))) from ex session_id = response.get("session_id") if self._session: self._session._session_id = session_id try: job = IBMCircuitJob( backend=self, api_client=self._api_client, runtime_client=self.provider._runtime_client, job_id=response["id"], session_id=session_id, ) logger.debug("Job %s was successfully submitted.", job.job_id()) except TypeError as err: logger.debug("Invalid job data received: %s", response) raise IBMBackendApiProtocolError( "Unexpected return value received from the server " "when submitting job: {}".format(str(err)) ) from err Publisher().publish("ibm.job.start", job) return job def _get_run_config(self, program_id: str, **kwargs: Any) -> Dict: """Return the consolidated runtime configuration.""" # Check if is a QASM3 like program id. if program_id.startswith(QASM3RUNNERPROGRAMID): fields = asdict(QASM3Options()).keys() run_config_dict = QASM3Options().to_transport_dict() else: fields = asdict(QASM2Options()).keys() run_config_dict = QASM2Options().to_transport_dict() backend_options = self._options.__dict__ for key, val in kwargs.items(): if val is not None: run_config_dict[key] = val if key not in fields and not self.configuration().simulator: warnings.warn( # type: ignore[unreachable] f"{key} is not a recognized runtime option and may be ignored by the backend.", stacklevel=4, ) elif backend_options.get(key) is not None and key in fields: run_config_dict[key] = backend_options[key] return run_config_dict
[docs] def properties( self, refresh: bool = False, datetime: Optional[python_datetime] = None ) -> Optional[BackendProperties]: """Return the backend properties, subject to optional filtering. This data describes qubits properties (such as T1 and T2), gates properties (such as gate length and error), and other general properties of the backend. The schema for backend properties can be found in `Qiskit/ibm-quantum-schemas <>`_. Args: refresh: If ``True``, re-query the server for the backend properties. Otherwise, return a cached version. datetime: By specifying `datetime`, this function returns an instance of the :class:`BackendProperties<qiskit.providers.models.BackendProperties>` whose timestamp is closest to, but older than, the specified `datetime`. Returns: The backend properties or ``None`` if the backend properties are not currently available. Raises: TypeError: If an input argument is not of the correct type. """ # 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 and not isinstance(datetime, python_datetime): raise TypeError("'{}' is not of type 'datetime'.") if datetime: datetime = local_to_utc(datetime) if datetime or refresh or self._properties is None: api_properties = self.provider._runtime_client.backend_properties(, datetime=datetime ) if not api_properties: return None backend_properties = properties_from_server_data(api_properties) if datetime: # Don't cache result. return backend_properties self._properties = backend_properties return self._properties
[docs] def status(self) -> BackendStatus: """Return the backend status. Note: If the returned :class:`~qiskit.providers.models.BackendStatus` instance has ``operational=True`` but ``status_msg="internal"``, then the backend is accepting jobs but not processing them. Returns: The status of the backend. Raises: IBMBackendApiProtocolError: If the status for the backend cannot be formatted properly. """ api_status = self.provider._runtime_client.backend_status( try: return BackendStatus.from_dict(api_status) except TypeError as ex: raise IBMBackendApiProtocolError( "Unexpected return value received from the server when " "getting backend status: {}".format(str(ex)) ) from ex
[docs] def defaults(self, refresh: bool = False) -> Optional[PulseDefaults]: """Return the pulse defaults for the backend. The schema for default pulse configuration can be found in `Qiskit/ibm-quantum-schemas <>`_. Args: refresh: If ``True``, re-query the server for the backend pulse defaults. Otherwise, return a cached version. Returns: The backend pulse defaults or ``None`` if the backend does not support pulse. """ if refresh or self._defaults is None: api_defaults = self.provider._runtime_client.backend_pulse_defaults( ) if api_defaults: self._defaults = defaults_from_server_data(api_defaults) else: self._defaults = None return self._defaults
[docs] def configuration( self, ) -> Union[QasmBackendConfiguration, PulseBackendConfiguration]: """Return the backend configuration. Backend configuration contains fixed information about the backend, such as its name, number of qubits, basis gates, coupling map, quantum volume, etc. The schema for backend configuration can be found in `Qiskit/ibm-quantum-schemas <>`_. Returns: The configuration for the backend. """ return self._configuration
[docs] def drive_channel(self, qubit: int) -> DriveChannel: """Return the drive channel for the given qubit. Returns: DriveChannel: The Qubit drive channel """ return
[docs] 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)
[docs] 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)
[docs] 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__, def _deprecate_id_instruction( 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` passed to :meth:`<>`. Modified in-place. Returns: A modified copy of the original circuit where 'id' instructions are replaced with 'delay' instructions. A copy is used so the original circuit is not modified. If there are no 'id' instructions or 'delay' is not supported, return the original circuit. """ id_support = "id" in getattr(self.configuration(), "basis_gates", []) delay_support = "delay" in getattr( self.configuration(), "supported_instructions", [] ) if not delay_support: return circuits circuit_has_id = any( == "id" for circuit in circuits if isinstance(circuit, QuantumCircuit) for instr, qargs, cargs in ) if not circuit_has_id: return circuits 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 # Make sure we don't mutate user's input circuits circuits = copy.deepcopy(circuits) # Convert id gates to delays. pm = PassManager( # pylint: disable=invalid-name ConvertIdToDelay( ) circuits = return circuits
[docs] @classmethod def get_translation_stage_plugin(cls) -> str: """Return the default translation stage plugin name for IBM backends.""" return "ibm_dynamic_circuits"
def _check_circuits_attributes(self, circuits: List[QuantumCircuit]) -> None: """Check that circuits can be executed on backend. Raises: IBMBackendValueError: - If one of the circuits contains more qubits than on the backend.""" 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, QuantumCircuit): if circ.num_qubits > self._configuration.num_qubits: raise IBMBackendValueError( f"Circuit contains {circ.num_qubits} qubits, " f"but backend has only {self.num_qubits}." ) self._check_faulty(circ) def _check_faulty(self, circuit: QuantumCircuit) -> None: """Check if the input circuit uses faulty qubits or edges. Args: circuit: Circuit to check. Raises: ValueError: If an instruction operating on a faulty qubit or edge is found. """ if not return faulty_qubits = faulty_gates = faulty_edges = [ tuple(gate.qubits) for gate in faulty_gates if len(gate.qubits) > 1 ] for instr in if == "barrier": continue qubit_indices = tuple(circuit.find_bit(x).index for x in instr.qubits) for circ_qubit in qubit_indices: if circ_qubit in faulty_qubits: raise ValueError( f"Circuit {} contains instruction " f"{instr} operating on a faulty qubit {circ_qubit}." ) if len(qubit_indices) == 2 and qubit_indices in faulty_edges: raise ValueError( f"Circuit {} contains instruction " f"{instr} operating on a faulty edge {qubit_indices}" )
[docs] def open_session(self, max_time: Optional[Union[int, str]] = None) -> Session: """Open session""" self._session = Session(max_time) return self._session
@property def session(self) -> Session: """Return session""" return self._session
[docs] def cancel_session(self) -> None: """Cancel session. All pending jobs will be cancelled.""" if self._session: self._session.cancel() if self._session.session_id: self.provider._runtime_client.cancel_session(self._session.session_id) self._session = None
[docs] def close_session(self) -> None: """Close the session so new jobs will no longer be accepted, but existing queued or running jobs will run to completion. The session will be terminated once there are no more pending jobs.""" if self._session: self._session.cancel() if self._session.session_id: self.provider._runtime_client.close_session(self._session.session_id) self._session = None
class IBMRetiredBackend(IBMBackend): """Backend class interfacing with an IBM Quantum device no longer available.""" def __init__( self, configuration: Union[QasmBackendConfiguration, PulseBackendConfiguration], provider: "ibm_provider.IBMProvider", api_client: AccountClient, ) -> None: """IBMRetiredBackend constructor. Args: configuration: Backend configuration. provider: IBM Quantum account provider. credentials: IBM Quantum credentials. api_client: IBM Quantum client used to communicate with the server. """ super().__init__(configuration, provider, api_client) self._status = BackendStatus(, backend_version=self.configuration().backend_version, operational=False, pending_jobs=0, status_msg="This backend is no longer available.", ) @classmethod def _default_options(cls) -> Options: """Default runtime options.""" return super()._default_options() def properties( self, refresh: bool = False, datetime: Optional[python_datetime] = None ) -> None: """Return the backend properties.""" return None def defaults(self, refresh: bool = False) -> None: """Return the pulse defaults for the backend.""" return None def status(self) -> BackendStatus: """Return the backend status.""" return self._status def run(self, *args: Any, **kwargs: Any) -> None: # type: ignore[override] """Run a Circuit.""" # pylint: disable=arguments-differ raise IBMBackendError( "This backend ({}) is no longer available.".format( ) @classmethod def from_name( cls, backend_name: str, provider: "ibm_provider.IBMProvider", api: AccountClient, ) -> "IBMRetiredBackend": """Return a retired backend from its 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, local=False, conditional=False, open_pulse=False, memory=False, max_shots=1, gates=[GateConfig(name="TODO", parameters=[], qasm_def="TODO")], coupling_map=[[0, 1]], max_experiments=300, ) return cls(configuration, provider, api)