Source code for qlauncher.routines.qiskit.backends.aqt_backend

  1"""AQT backend class for Qiskit routines"""
  2
  3from typing import Literal
  4
  5from overrides import override
  6from qiskit.primitives import BaseEstimatorV2, BaseSamplerV2
  7from qiskit.providers import BackendV1, BackendV2
  8from qiskit_ibm_runtime import Options
  9
 10from qlauncher.exceptions import DependencyError
 11from qlauncher.routines.qiskit.adapters import (
 12    EstimatorV1ToEstimatorV2Adapter,
 13    SamplerV1ToSamplerV2Adapter,
 14    TranslatingSampler,
 15    TranslatingSamplerV1,
 16)
 17from qlauncher.routines.qiskit.backends.qiskit_backend import QiskitBackend
 18from qlauncher.routines.qiskit.mitigation_suppression.base import CircuitExecutionMethod
 19
 20try:
 21    from qiskit_aqt_provider import AQTProvider
 22    from qiskit_aqt_provider.primitives import AQTEstimator, AQTSampler
 23except ImportError as e:
 24    raise DependencyError(e, install_hint='aqt') from e
 25
 26
[docs] 27class AQTBackend(QiskitBackend): 28 """ 29 An extension of QiskitBackend providing support for Alpine Quantum Technologies (AQT) devices. 30 31 Attributes: 32 token (str, optional): AQT token, used for authorization when using real device backends. 33 dotenv_path (str,optional): (recommended) Path to a .env file containing the AQT token. If dotenv_path is not None, the token will be ignored and the token from the .env file will be used. 34 35 Usage Example 36 ------------- 37 :: 38 39 backend = AQTBackend(token='valid_token', name='device') 40 41 or 42 43 :: 44 45 backend = AQTBackend(dotenv_path='./.env', name='device') 46 47 with a .env file: 48 49 :: 50 51 AQT_TOKEN = valid_token 52 53 """ 54 55 sampler: BaseSamplerV2 56 estimator: BaseEstimatorV2 57 58 def __init__( 59 self, 60 name: Literal['local_simulator', 'backendv1v2', 'device'], 61 options: Options | None = None, 62 backendv1v2: BackendV1 | BackendV2 | None = None, 63 auto_transpile_level: Literal[0, 1, 2, 3] | None = None, 64 error_mitigation_strategy: CircuitExecutionMethod | None = None, 65 token: str | None = None, 66 direct_access_url: str | None = None, 67 dotenv_path: str | None = None, 68 ) -> None: 69 self._direct_access_url = direct_access_url 70 if dotenv_path is None: 71 self.provider = AQTProvider(token if token is not None else 'DEFAULT_TOKEN', load_dotenv=False) 72 else: 73 self.provider = AQTProvider(load_dotenv=True, dotenv_path=dotenv_path) 74 super().__init__( 75 name, 76 options=options, 77 backendv1v2=backendv1v2, 78 auto_transpile_level=auto_transpile_level, 79 error_mitigation_strategy=error_mitigation_strategy, 80 ) 81 82 @override 83 def _set_primitives_on_backend_name(self) -> None: 84 if self.name == 'local_simulator': 85 self.name = self.provider.backends(backend_type='offline_simulator', name=r'.*no_noise')[0].name 86 elif self.name == 'backendv1v2': 87 if self.backendv1v2 is None and self._direct_access_url: 88 self.backendv1v2 = self.provider.get_direct_access_backend(self._direct_access_url) 89 elif self.backendv1v2 is None: 90 raise ValueError('Please indicate a backend when in backendv1v2 mode.') 91 elif self.name == 'device': 92 available_online_backends = self.provider.backends(backend_type='device') 93 if len(available_online_backends) == 0: 94 raise ValueError(f'No online backends available for token {self.provider.access_token[:5]}...') 95 self.name = available_online_backends[0].name 96 else: 97 raise ValueError( 98 ' '.join( 99 [ 100 f"Unsupported mode for this backend:'{self.name}'." 101 "Please use one of the following: ['local_simulator', 'backendv1v2', 'device']" 102 ] 103 ) 104 ) 105 106 if self.backendv1v2 is None: 107 self.backendv1v2 = self.provider.get_backend(name=self.name) 108 109 self._estimatorv1 = AQTEstimator(self.backendv1v2) 110 self.estimator = EstimatorV1ToEstimatorV2Adapter(self._estimatorv1) 111 self._samplerV1 = TranslatingSamplerV1(AQTSampler(self.backendv1v2), self.compatible_circuit) 112 self.sampler = SamplerV1ToSamplerV2Adapter(self._samplerV1) 113 114 self._configure_auto_behavior()