Source code for quantum_launcher.routines.qiskit_routines.backends.aqt_backend

 1""" AQT backend class for Qiskit routines """
 2from typing import Literal
 3from overrides import override
 4
 5from qiskit.providers import BackendV1, BackendV2
 6from qiskit.primitives import Sampler
 7from qiskit_algorithms.optimizers import COBYLA, SPSA
 8from qiskit_ibm_runtime import Options
 9
10from quantum_launcher.routines.qiskit_routines import QiskitBackend
11from quantum_launcher.exceptions import DependencyError
12
13try:
14    from qiskit_aqt_provider import AQTProvider
15    from qiskit_aqt_provider.primitives import AQTSampler, AQTEstimator
16except ImportError as e:
17    raise DependencyError(e, install_hint='aqt') from e
18
19
[docs] 20class AQTBackend(QiskitBackend): 21 """ 22 An extension of QiskitBackend providing support for Alpine Quantum Technologies (AQT) devices. 23 24 Attributes: 25 token (str, optional): AQT token, used for authorization when using real device backends. 26 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. 27 28 Usage Example 29 ------------- 30 :: 31 32 backend = AQTBackend(token='valid_token', name='device') 33 34 or 35 36 :: 37 38 backend = AQTBackend(dotenv_path='./.env', name='device') 39 40 with a .env file: 41 42 :: 43 44 AQT_TOKEN=valid_token 45 46 """ 47 sampler: AQTSampler 48 estimator: AQTEstimator 49 50 def __init__( 51 self, 52 name: Literal['local_simulator', 'backendv1v2', 'device'], 53 options: Options | None = None, 54 backendv1v2: BackendV1 | BackendV2 | None = None, 55 auto_transpile_level: Literal[0, 1, 2, 3] | None = None, 56 token: str | None = None, 57 dotenv_path: str | None = None, 58 ) -> None: 59 60 # TODO: This will probably need to be updated to handle custom backend urls, when we get our own computer 61 if dotenv_path is None: 62 self.provider = AQTProvider(token if token is not None else "DEFAULT_TOKEN", load_dotenv=False) 63 else: 64 self.provider = AQTProvider(load_dotenv=True, dotenv_path=dotenv_path) 65 super().__init__(name, options=options, backendv1v2=backendv1v2, auto_transpile_level=auto_transpile_level) 66 67 @override 68 def _set_primitives_on_backend_name(self) -> None: 69 if self.name == 'local_simulator': 70 self.name = self.provider.backends(backend_type='offline_simulator', name=r".*no_noise")[0].name 71 elif self.name == 'backendv1v2': 72 if self.backendv1v2 is None: 73 raise ValueError("Please indicate a backend when in backendv1v2 mode.") 74 elif self.name == 'device': 75 available_online_backends = self.provider.backends(backend_type='device') 76 if len(available_online_backends) == 0: 77 raise ValueError(f"No online backends available for token {self.provider.access_token[:5]}...") 78 self.name = available_online_backends[0].name 79 else: 80 raise ValueError( 81 " ".join([ 82 f"Unsupported mode for this backend:'{self.name}'." 83 "Please use one of the following: ['local_simulator', 'backendv1v2', 'device']" 84 ]) 85 ) 86 87 if self.backendv1v2 is None: 88 self.backendv1v2 = self.provider.get_backend(name=self.name) 89 90 self.estimator = AQTEstimator(self.backendv1v2) 91 self.sampler = AQTSampler(self.backendv1v2) 92 self.optimizer = SPSA() if self.name == 'device' else COBYLA() 93 94 self._configure_auto_behavior() 95 96 @property 97 def samplerV1(self) -> Sampler: 98 return self.sampler