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

  1""" Base backend class for Qiskit routines. """
  2from typing import Literal
  3
  4from qiskit.providers import BackendV1, BackendV2
  5from qiskit.primitives import (
  6    BackendSamplerV2,
  7    BackendEstimatorV2,
  8    StatevectorEstimator,
  9    StatevectorSampler,
 10    Sampler
 11)
 12
 13from qiskit_ibm_runtime import Options
 14
 15from qlauncher.base import Backend
 16from qlauncher.routines.qiskit.v2_wrapper import SamplerV2Adapter
 17
 18from qlauncher.routines.qiskit.backends.utils import (
 19    set_estimator_auto_run_behavior, set_sampler_auto_run_behavior,
 20    AUTO_TRANSPILE_ESTIMATOR_TYPE, AUTO_TRANSPILE_SAMPLER_TYPE
 21)
 22
 23
[docs] 24class QiskitBackend(Backend): 25 """ 26 Base class for backends compatible with qiskit. 27 28 Attributes: 29 name (str): The name of the backend. 30 options (Options | None, optional): The options for the backend. Defaults to None. 31 backendv1v2 (BackendV1 | BackendV2 | None, optional): Predefined backend to use with name 'backendv1v2'. Defaults to None. 32 sampler (BaseSamplerV2): The sampler used for sampling. 33 estimator (BaseEstimatorV2): The estimator used for estimation. 34 """ 35 36 def __init__( 37 self, 38 name: Literal['local_simulator', 'backendv1v2'] | str, 39 options: Options | None = None, 40 backendv1v2: BackendV1 | BackendV2 | None = None, 41 auto_transpile_level: Literal[0, 1, 2, 3] | None = None 42 ) -> None: 43 """ 44 Args: 45 **name (Literal['local_simulator', 'backendv1v2'] | str)**: Name or mode of operation, 46 'backendv1v2' allows for using a specific backend simulator. 47 **options (Options | None, optional)**: Defaults to None. 48 **backendv1v2 (BackendV1 | BackendV2 | None, optional)**: 49 Used with name 'backendv1v2', sampler and estimator will use it. Defaults to None. 50 **auto_transpile_level (Literal[0, 1, 2, 3] | None, optional)**: 51 Optimization level for automatic transpilation of circuits. 52 - None: Don't transpile. 53 - 0: No optimization (only transpile to compatible gates). 54 - 1: Light optimization. 55 - 2: Heavy optimization. 56 - 3: Heaviest optimization. 57 Defaults to None. 58 """ 59 super().__init__(name) 60 self.options = options 61 self.backendv1v2 = backendv1v2 62 self._auto_transpile_level = auto_transpile_level 63 self._auto_assign = False 64 self._samplerV1: Sampler | None = None 65 self._set_primitives_on_backend_name() 66 67 @property 68 def samplerV1(self) -> Sampler: 69 if self._samplerV1 is None: 70 self._samplerV1 = SamplerV2Adapter(self.sampler) 71 return self._samplerV1 72 73 def _set_primitives_on_backend_name(self): 74 if self.name == 'local_simulator': 75 self.estimator = StatevectorEstimator() 76 self.sampler = StatevectorSampler() 77 elif self.name == 'backendv1v2': 78 if self.backendv1v2 is None: 79 raise AttributeError( 80 'Please indicate a backend when in backendv1v2 mode.') 81 self.estimator = BackendEstimatorV2(backend=self.backendv1v2) 82 self.sampler = BackendSamplerV2(backend=self.backendv1v2) 83 84 else: 85 raise ValueError(f"Unsupported mode for this backend:'{self.name}'") 86 87 self._configure_auto_behavior() 88 89 def _configure_auto_behavior(self): 90 """ 91 Set auto transpilation and/or auto assignment if turned on, on estimator and sampler if compatible. 92 """ 93 do_transpile, level = self._auto_transpile_level != None, int( 94 self._auto_transpile_level if self._auto_transpile_level != None else 0) 95 if isinstance(self.estimator, AUTO_TRANSPILE_ESTIMATOR_TYPE.__constraints__): 96 self.estimator = set_estimator_auto_run_behavior( 97 self.estimator, 98 auto_transpile=do_transpile, 99 auto_transpile_level=level, 100 auto_assign=self._auto_assign 101 ) 102 if isinstance(self.sampler, AUTO_TRANSPILE_SAMPLER_TYPE.__constraints__): 103 self.sampler = set_sampler_auto_run_behavior( 104 self.sampler, 105 auto_transpile=do_transpile, 106 auto_transpile_level=level, 107 auto_assign=self._auto_assign 108 )