13
13
"""Provider for a single IBM Quantum Experience account."""
14
14
15
15
import logging
16
- from typing import Dict , List , Optional , Any , Callable
16
+ from typing import Dict , List , Optional , Any , Callable , Union
17
17
from collections import OrderedDict
18
18
import traceback
19
19
20
20
from qiskit .providers import ProviderV1 as Provider # type: ignore[attr-defined]
21
21
from qiskit .providers .models import (QasmBackendConfiguration ,
22
22
PulseBackendConfiguration )
23
+ from qiskit .circuit import QuantumCircuit
24
+ from qiskit .providers .backend import BackendV1 as Backend
25
+ from qiskit .providers .basebackend import BaseBackend
26
+ from qiskit .transpiler import Layout
27
+ from qiskit .providers .ibmq .runtime import runtime_job # pylint: disable=unused-import
23
28
24
29
from .api .clients import AccountClient
25
30
from .ibmqbackend import IBMQBackend , IBMQSimulator
28
33
from .utils .json_decoder import decode_backend_configuration
29
34
from .random .ibmqrandomservice import IBMQRandomService
30
35
from .experiment .experimentservice import ExperimentService
36
+ from .runtime .ibm_runtime_service import IBMRuntimeService
31
37
from .exceptions import IBMQNotAuthorizedError , IBMQInputValueError
32
38
33
39
logger = logging .getLogger (__name__ )
@@ -89,18 +95,16 @@ class AccountProvider(Provider):
89
95
in Jupyter Notebook and the Python interpreter.
90
96
"""
91
97
92
- def __init__ (self , credentials : Credentials , access_token : str ) -> None :
98
+ def __init__ (self , credentials : Credentials ) -> None :
93
99
"""AccountProvider constructor.
94
100
95
101
Args:
96
102
credentials: IBM Quantum Experience credentials.
97
- access_token: IBM Quantum Experience access token.
98
103
"""
99
104
super ().__init__ ()
100
105
101
106
self .credentials = credentials
102
- self ._api_client = AccountClient (access_token ,
103
- credentials ,
107
+ self ._api_client = AccountClient (credentials ,
104
108
** credentials .connection_parameters ())
105
109
106
110
# Initialize the internal list of backends.
@@ -109,14 +113,15 @@ def __init__(self, credentials: Credentials, access_token: str) -> None:
109
113
self .backends = IBMQDeprecatedBackendService (self .backend ) # type: ignore[assignment]
110
114
111
115
# Initialize other services.
112
- self ._random = IBMQRandomService (self , access_token ) \
113
- if credentials .extractor_url else None
114
- self ._experiment = ExperimentService (self , access_token ) \
115
- if credentials .experiment_url else None
116
+ self ._random = IBMQRandomService (self ) if credentials . extractor_url else None
117
+ self . _experiment = ExperimentService ( self ) if credentials .experiment_url else None
118
+ self ._runtime = IBMRuntimeService (self ) \
119
+ if credentials .runtime_url else None
116
120
117
121
self ._services = {'backend' : self ._backend ,
118
122
'random' : self ._random ,
119
- 'experiment' : self ._experiment }
123
+ 'experiment' : self ._experiment ,
124
+ 'runtime' : self ._runtime }
120
125
121
126
def backends (
122
127
self ,
@@ -188,6 +193,102 @@ def _discover_remote_backends(self, timeout: Optional[float] = None) -> Dict[str
188
193
189
194
return ret
190
195
196
+ def run_circuits (
197
+ self ,
198
+ circuits : Union [QuantumCircuit , List [QuantumCircuit ]],
199
+ backend : Union [Backend , BaseBackend ],
200
+ shots : Optional [int ] = None ,
201
+ initial_layout : Optional [Union [Layout , Dict , List ]] = None ,
202
+ layout_method : Optional [str ] = None ,
203
+ routing_method : Optional [str ] = None ,
204
+ translation_method : Optional [str ] = None ,
205
+ seed_transpiler : Optional [int ] = None ,
206
+ optimization_level : Optional [int ] = None ,
207
+ init_qubits : Optional [bool ] = True ,
208
+ rep_delay : Optional [float ] = None ,
209
+ transpiler_options : Optional [dict ] = None ,
210
+ measurement_error_mitigation : Optional [bool ] = False ,
211
+ ** run_config : Dict
212
+ ) -> 'runtime_job.RuntimeJob' :
213
+ """Execute the input circuit(s) on a backend using the runtime service.
214
+
215
+ Note:
216
+ This method uses the IBM Quantum runtime service which is not
217
+ available to all accounts.
218
+
219
+ Note:
220
+ This method returns a :class:``~qiskit.provider.ibmq.runtime.RuntimeJob``.
221
+ To get the job result, you'll need to use the
222
+ ``qiskit_runtime.circuit_runner.RunnerResult`` class
223
+ as the ``decoder``, e.g.::
224
+
225
+ result = provider.run_circuits(...).result(decoder=RunnerResult)
226
+
227
+ You can find more about the ``RunnerResult`` class in the
228
+ `qiskit-runtime repository <https://github.com/Qiskit-Partners/qiskit-runtime>`_.
229
+
230
+ Args:
231
+ circuits: Circuit(s) to execute.
232
+
233
+ backend: Backend to execute circuits on.
234
+ Transpiler options are automatically grabbed from backend configuration
235
+ and properties unless otherwise specified.
236
+
237
+ initial_layout: Initial position of virtual qubits on physical qubits.
238
+
239
+ layout_method: Name of layout selection pass ('trivial', 'dense',
240
+ 'noise_adaptive', 'sabre').
241
+ Sometimes a perfect layout can be available in which case the layout_method
242
+ may not run.
243
+
244
+ routing_method: Name of routing pass ('basic', 'lookahead', 'stochastic', 'sabre')
245
+
246
+ translation_method: Name of translation pass ('unroller', 'translator', 'synthesis')
247
+
248
+ seed_transpiler: Sets random seed for the stochastic parts of the transpiler.
249
+
250
+ optimization_level: How much optimization to perform on the circuits.
251
+ Higher levels generate more optimized circuits, at the expense of longer
252
+ transpilation time.
253
+ If None, level 1 will be chosen as default.
254
+
255
+ shots: Number of repetitions of each circuit, for sampling. Default: 1024.
256
+
257
+ rep_delay: Delay between programs in seconds. Only supported on certain
258
+ backends (``backend.configuration().dynamic_reprate_enabled`` ). If supported,
259
+ ``rep_delay`` will be used instead of ``rep_time`` and must be from the
260
+ range supplied by the backend (``backend.configuration().rep_delay_range``).
261
+ Default is given by ``backend.configuration().default_rep_delay``.
262
+
263
+ init_qubits: Whether to reset the qubits to the ground state for each shot.
264
+
265
+ transpiler_options: Additional transpiler options.
266
+
267
+ measurement_error_mitigation: Whether to apply measurement error mitigation.
268
+
269
+ **run_config: Extra arguments used to configure the circuit execution.
270
+
271
+ Returns:
272
+ Runtime job.
273
+ """
274
+ inputs = {
275
+ 'circuits' : circuits ,
276
+ 'initial_layout' : initial_layout ,
277
+ 'seed_transpiler' : seed_transpiler ,
278
+ 'optimization_level' : optimization_level ,
279
+ 'layout_method' : layout_method ,
280
+ 'shots' : shots ,
281
+ 'routing_method' : routing_method ,
282
+ 'translation_method' : translation_method ,
283
+ 'rep_delay' : rep_delay ,
284
+ 'init_qubits' : init_qubits ,
285
+ 'transpiler_options' : transpiler_options ,
286
+ 'measurement_error_mitigation' : measurement_error_mitigation
287
+ }
288
+ inputs .update (run_config )
289
+ options = {'backend_name' : backend .name ()}
290
+ return self .runtime .run ('circuit-runner' , options = options , inputs = inputs )
291
+
191
292
def service (self , name : str ) -> Any :
192
293
"""Return the specified service.
193
294
@@ -218,6 +319,26 @@ def services(self) -> Dict:
218
319
"""
219
320
return {key : val for key , val in self ._services .items () if val is not None }
220
321
322
+ def has_service (self , name : str ) -> bool :
323
+ """Check if this provider has access to the service.
324
+
325
+ Args:
326
+ name: Name of the service.
327
+
328
+ Returns:
329
+ Whether the provider has access to the service.
330
+
331
+ Raises:
332
+ IBMQInputValueError: If an unknown service name is specified.
333
+ """
334
+ if name not in self ._services :
335
+ raise IBMQInputValueError (f"Unknown service { name } specified." )
336
+
337
+ if self ._services [name ] is None :
338
+ return False
339
+
340
+ return True
341
+
221
342
@property
222
343
def backend (self ) -> IBMQBackendService :
223
344
"""Return the backend service.
@@ -257,7 +378,22 @@ def random(self) -> IBMQRandomService:
257
378
if self ._random :
258
379
return self ._random
259
380
else :
260
- raise IBMQNotAuthorizedError ("You are not authorized to use the random number service." )
381
+ raise IBMQNotAuthorizedError ("You are not authorized to use the service." )
382
+
383
+ @property
384
+ def runtime (self ) -> IBMRuntimeService :
385
+ """Return the runtime service.
386
+
387
+ Returns:
388
+ The runtime service instance.
389
+
390
+ Raises:
391
+ IBMQNotAuthorizedError: If the account is not authorized to use the service.
392
+ """
393
+ if self ._runtime :
394
+ return self ._runtime
395
+ else :
396
+ raise IBMQNotAuthorizedError ("You are not authorized to use the runtime service." )
261
397
262
398
def __eq__ (
263
399
self ,
0 commit comments