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