55
55
from pytket .backends .backendinfo import BackendInfo
56
56
from pytket .backends .backendresult import BackendResult
57
57
from pytket .backends .resulthandle import _ResultIdTuple
58
- from pytket .extensions .qiskit .qiskit_convert import (
59
- process_characterisation ,
58
+ from ..qiskit_convert import (
60
59
get_avg_characterisation ,
60
+ process_characterisation_from_config ,
61
61
)
62
- from pytket . extensions . qiskit ._metadata import __extension_version__
62
+ from . ._metadata import __extension_version__
63
63
from pytket .passes import (
64
64
BasePass ,
65
65
auto_rebase_pass ,
82
82
NoFastFeedforwardPredicate ,
83
83
MaxNQubitsPredicate ,
84
84
Predicate ,
85
+ DirectednessPredicate ,
85
86
)
86
- from pytket .extensions .qiskit .qiskit_convert import tk_to_qiskit , _tk_gate_set
87
- from pytket .architecture import FullyConnected
87
+ from qiskit .providers .models import BackendProperties , QasmBackendConfiguration # type: ignore
88
+
89
+ from ..qiskit_convert import tk_to_qiskit , _tk_gate_set
90
+ from pytket .architecture import FullyConnected , Architecture
88
91
from pytket .placement import NoiseAwarePlacement
89
92
from pytket .utils import prepare_circuit
90
93
from pytket .utils .outcomearray import OutcomeArray
@@ -190,11 +193,12 @@ def __init__(
190
193
else provider
191
194
)
192
195
self ._backend : "_QiskIBMBackend" = self ._provider .get_backend (backend_name )
193
- config = self ._backend .configuration ()
196
+ config : QasmBackendConfiguration = self ._backend .configuration ()
194
197
self ._max_per_job = getattr (config , "max_experiments" , 1 )
195
198
196
- gate_set = _tk_gate_set (self ._backend )
197
- self ._backend_info = self ._get_backend_info (self ._backend )
199
+ gate_set = _tk_gate_set (config )
200
+ props : Optional [BackendProperties ] = self ._backend .properties ()
201
+ self ._backend_info = self ._get_backend_info (config , props )
198
202
199
203
self ._service = QiskitRuntimeService (
200
204
channel = "ibm_quantum" , token = token , instance = instance
@@ -239,9 +243,21 @@ def backend_info(self) -> BackendInfo:
239
243
return self ._backend_info
240
244
241
245
@classmethod
242
- def _get_backend_info (cls , backend : "_QiskIBMBackend" ) -> BackendInfo :
243
- config = backend .configuration ()
244
- characterisation = process_characterisation (backend )
246
+ def _get_backend_info (
247
+ cls ,
248
+ config : QasmBackendConfiguration ,
249
+ props : Optional [BackendProperties ],
250
+ ) -> BackendInfo :
251
+ """Construct a BackendInfo from data returned by the IBMQ API.
252
+
253
+ :param config: The configuration of this backend.
254
+ :type config: QasmBackendConfiguration
255
+ :param props: The measured properties of this backend (not required).
256
+ :type props: Optional[BackendProperties]
257
+ :return: Information about the backend.
258
+ :rtype: BackendInfo
259
+ """
260
+ characterisation = process_characterisation_from_config (config , props )
245
261
averaged_errors = get_avg_characterisation (characterisation )
246
262
characterisation_keys = [
247
263
"t1times" ,
@@ -270,10 +286,10 @@ def _get_backend_info(cls, backend: "_QiskIBMBackend") -> BackendInfo:
270
286
hasattr (config , "supported_instructions" )
271
287
and "reset" in config .supported_instructions
272
288
)
273
- gate_set = _tk_gate_set (backend )
289
+ gate_set = _tk_gate_set (config )
274
290
backend_info = BackendInfo (
275
291
cls .__name__ ,
276
- backend . name ,
292
+ config . backend_name ,
277
293
__extension_version__ ,
278
294
arch ,
279
295
(
@@ -310,9 +326,12 @@ def available_devices(cls, **kwargs: Any) -> List[BackendInfo]:
310
326
else :
311
327
provider = IBMProvider ()
312
328
313
- backend_info_list = [
314
- cls ._get_backend_info (backend ) for backend in provider .backends ()
315
- ]
329
+ backend_info_list = []
330
+ for backend in provider .backends ():
331
+ config = backend .configuration ()
332
+ props = backend .properties ()
333
+ backend_info_list .append (cls ._get_backend_info (config , props ))
334
+
316
335
return backend_info_list
317
336
318
337
@property
@@ -328,17 +347,16 @@ def required_predicates(self) -> List[Predicate]:
328
347
)
329
348
),
330
349
]
350
+ if isinstance (self .backend_info .architecture , Architecture ):
351
+ predicates .append (DirectednessPredicate (self .backend_info .architecture ))
352
+
331
353
mid_measure = self ._backend_info .supports_midcircuit_measurement
332
354
fast_feedforward = self ._backend_info .supports_fast_feedforward
333
355
if not mid_measure :
334
- predicates = [
335
- NoClassicalControlPredicate (),
336
- NoMidMeasurePredicate (),
337
- ] + predicates
356
+ predicates .append (NoClassicalControlPredicate ())
357
+ predicates .append (NoMidMeasurePredicate ())
338
358
if not fast_feedforward :
339
- predicates = [
340
- NoFastFeedforwardPredicate (),
341
- ] + predicates
359
+ predicates .append (NoFastFeedforwardPredicate ())
342
360
return predicates
343
361
344
362
def default_compilation_pass (
@@ -376,47 +394,64 @@ def default_compilation_pass(
376
394
:return: Compilation pass guaranteeing required predicates.
377
395
:rtype: BasePass
378
396
"""
397
+ config : QasmBackendConfiguration = self ._backend .configuration ()
398
+ props : Optional [BackendProperties ] = self ._backend .properties ()
399
+ return IBMQBackend .default_compilation_pass_offline (
400
+ config , props , optimisation_level , placement_options
401
+ )
402
+
403
+ @staticmethod
404
+ def default_compilation_pass_offline (
405
+ config : QasmBackendConfiguration ,
406
+ props : Optional [BackendProperties ],
407
+ optimisation_level : int = 2 ,
408
+ placement_options : Optional [Dict ] = None ,
409
+ ) -> BasePass :
410
+ backend_info = IBMQBackend ._get_backend_info (config , props )
411
+ primitive_gates = _get_primitive_gates (_tk_gate_set (config ))
412
+ supports_rz = OpType .Rz in primitive_gates
413
+
379
414
assert optimisation_level in range (3 )
380
415
passlist = [DecomposeBoxes ()]
381
416
# If you make changes to the default_compilation_pass,
382
417
# then please update this page accordingly
383
418
# https://tket.quantinuum.com/extensions/pytket-qiskit/index.html#default-compilation
384
419
# Edit this docs source file -> pytket-qiskit/docs/intro.txt
385
420
if optimisation_level == 0 :
386
- if self . _supports_rz :
421
+ if supports_rz :
387
422
# If the Rz gate is unsupported then the rebase should be skipped
388
423
# This prevents an error when compiling to the stabilizer backend
389
424
# where no TK1 replacement can be found for the rebase.
390
- passlist .append (self . rebase_pass ( ))
425
+ passlist .append (IBMQBackend . rebase_pass_offline ( primitive_gates ))
391
426
elif optimisation_level == 1 :
392
427
passlist .append (SynthesiseTket ())
393
428
elif optimisation_level == 2 :
394
429
passlist .append (FullPeepholeOptimise ())
395
- mid_measure = self . _backend_info .supports_midcircuit_measurement
396
- arch = self . _backend_info .architecture
430
+ mid_measure = backend_info .supports_midcircuit_measurement
431
+ arch = backend_info .architecture
397
432
assert arch is not None
398
433
if not isinstance (arch , FullyConnected ):
399
434
if placement_options is not None :
400
435
noise_aware_placement = NoiseAwarePlacement (
401
436
arch ,
402
- self . _backend_info .averaged_node_gate_errors , # type: ignore
403
- self . _backend_info .averaged_edge_gate_errors , # type: ignore
404
- self . _backend_info .averaged_readout_errors , # type: ignore
437
+ backend_info .averaged_node_gate_errors , # type: ignore
438
+ backend_info .averaged_edge_gate_errors , # type: ignore
439
+ backend_info .averaged_readout_errors , # type: ignore
405
440
** placement_options ,
406
441
)
407
442
else :
408
443
noise_aware_placement = NoiseAwarePlacement (
409
444
arch ,
410
- self . _backend_info .averaged_node_gate_errors , # type: ignore
411
- self . _backend_info .averaged_edge_gate_errors , # type: ignore
412
- self . _backend_info .averaged_readout_errors , # type: ignore
445
+ backend_info .averaged_node_gate_errors , # type: ignore
446
+ backend_info .averaged_edge_gate_errors , # type: ignore
447
+ backend_info .averaged_readout_errors , # type: ignore
413
448
)
414
449
415
450
passlist .append (
416
451
CXMappingPass (
417
452
arch ,
418
453
noise_aware_placement ,
419
- directed_cx = False ,
454
+ directed_cx = True ,
420
455
delay_measures = (not mid_measure ),
421
456
)
422
457
)
@@ -432,8 +467,10 @@ def default_compilation_pass(
432
467
]
433
468
)
434
469
435
- if self ._supports_rz :
436
- passlist .extend ([self .rebase_pass (), RemoveRedundancies ()])
470
+ if supports_rz :
471
+ passlist .extend (
472
+ [IBMQBackend .rebase_pass_offline (primitive_gates ), RemoveRedundancies ()]
473
+ )
437
474
return SequencePass (passlist )
438
475
439
476
@property
@@ -442,7 +479,11 @@ def _result_id_type(self) -> _ResultIdTuple:
442
479
return (str , int , int , str )
443
480
444
481
def rebase_pass (self ) -> BasePass :
445
- return auto_rebase_pass (self ._primitive_gates )
482
+ return IBMQBackend .rebase_pass_offline (self ._primitive_gates )
483
+
484
+ @staticmethod
485
+ def rebase_pass_offline (primitive_gates : set [OpType ]) -> BasePass :
486
+ return auto_rebase_pass (primitive_gates )
446
487
447
488
def process_circuits (
448
489
self ,
0 commit comments