Skip to content

Commit 2806a04

Browse files
committed
Add fast transpilation method to BaseExperiment
1 parent d7df5f0 commit 2806a04

File tree

10 files changed

+277
-83
lines changed

10 files changed

+277
-83
lines changed

qiskit_experiments/calibration_management/base_calibration_experiment.py

Lines changed: 4 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,13 @@
2121
from qiskit import QuantumCircuit
2222
from qiskit.providers.options import Options
2323
from qiskit.pulse import ScheduleBlock
24-
from qiskit.transpiler import StagedPassManager, PassManager, Layout, CouplingMap
25-
from qiskit.transpiler.passes import (
26-
EnlargeWithAncilla,
27-
FullAncillaAllocation,
28-
ApplyLayout,
29-
SetLayout,
30-
)
3124

3225
from qiskit_experiments.calibration_management.calibrations import Calibrations
3326
from qiskit_experiments.calibration_management.update_library import BaseUpdater
3427
from qiskit_experiments.framework.base_analysis import BaseAnalysis
3528
from qiskit_experiments.framework.base_experiment import BaseExperiment
3629
from qiskit_experiments.framework.experiment_data import ExperimentData
30+
from qiskit_experiments.framework.transpilation import map_qubits, minimal_transpile
3731
from qiskit_experiments.exceptions import CalibrationError
3832

3933
LOG = logging.getLogger(__name__)
@@ -198,20 +192,6 @@ def _default_experiment_options(cls) -> Options:
198192
options.update_options(result_index=-1, group="default")
199193
return options
200194

201-
@classmethod
202-
def _default_transpile_options(cls) -> Options:
203-
"""Return empty default transpile options as optimization_level is not used."""
204-
return Options()
205-
206-
def set_transpile_options(self, **fields):
207-
r"""Add a warning message.
208-
209-
.. note::
210-
If your experiment has overridden `_transpiled_circuits` and needs
211-
transpile options then please also override `set_transpile_options`.
212-
"""
213-
warnings.warn(f"Transpile options are not used in {self.__class__.__name__ }.")
214-
215195
def update_calibrations(self, experiment_data: ExperimentData):
216196
"""Update parameter values in the :class:`.Calibrations` instance.
217197
@@ -295,42 +275,13 @@ def _transpiled_circuits(self) -> List[QuantumCircuit]:
295275
Returns:
296276
A list of transpiled circuits.
297277
"""
298-
transpiled = []
299-
for circ in self.circuits():
300-
circ = self._map_to_physical_qubits(circ)
278+
circuits = [map_qubits(c, self.physical_qubits) for c in self.circuits()]
279+
for circ in circuits:
301280
self._attach_calibrations(circ)
302-
303-
transpiled.append(circ)
281+
transpiled = minimal_transpile(circuits, self.backend, self.transpile_options)
304282

305283
return transpiled
306284

307-
def _map_to_physical_qubits(self, circuit: QuantumCircuit) -> QuantumCircuit:
308-
"""Map program qubits to physical qubits.
309-
310-
Args:
311-
circuit: The quantum circuit to map to device qubits.
312-
313-
Returns:
314-
A quantum circuit that has the same number of qubits as the backend and where
315-
the physical qubits of the experiment have been properly mapped.
316-
"""
317-
initial_layout = Layout.from_intlist(list(self.physical_qubits), *circuit.qregs)
318-
319-
coupling_map = self._backend_data.coupling_map
320-
if coupling_map is not None:
321-
coupling_map = CouplingMap(self._backend_data.coupling_map)
322-
323-
layout = PassManager(
324-
[
325-
SetLayout(initial_layout),
326-
FullAncillaAllocation(coupling_map),
327-
EnlargeWithAncilla(),
328-
ApplyLayout(),
329-
]
330-
)
331-
332-
return StagedPassManager(["layout"], layout=layout).run(circuit)
333-
334285
@abstractmethod
335286
def _attach_calibrations(self, circuit: QuantumCircuit):
336287
"""Attach the calibrations to the quantum circuit.

qiskit_experiments/framework/base_experiment.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,23 @@
1313
Base Experiment class.
1414
"""
1515

16-
from abc import ABC, abstractmethod
1716
import copy
17+
from abc import ABC, abstractmethod
1818
from collections import OrderedDict
1919
from typing import Sequence, Optional, Tuple, List, Dict, Union
2020

21-
from qiskit import transpile, QuantumCircuit
21+
from qiskit import QuantumCircuit
2222
from qiskit.providers import Job, Backend
2323
from qiskit.exceptions import QiskitError
2424
from qiskit.qobj.utils import MeasLevel
2525
from qiskit.providers.options import Options
2626
from qiskit_experiments.framework import BackendData
2727
from qiskit_experiments.framework.store_init_args import StoreInitArgs
28+
from qiskit_experiments.framework.transpilation import (
29+
DEFAULT_TRANSPILE_OPTIONS,
30+
map_qubits,
31+
minimal_transpile,
32+
)
2833
from qiskit_experiments.framework.base_analysis import BaseAnalysis
2934
from qiskit_experiments.framework.experiment_data import ExperimentData
3035
from qiskit_experiments.framework.configs import ExperimentConfig
@@ -373,9 +378,8 @@ def _transpiled_circuits(self) -> List[QuantumCircuit]:
373378
374379
This function can be overridden to define custom transpilation.
375380
"""
376-
transpile_opts = copy.copy(self.transpile_options.__dict__)
377-
transpile_opts["initial_layout"] = list(self.physical_qubits)
378-
transpiled = transpile(self.circuits(), self.backend, **transpile_opts)
381+
circuits = [map_qubits(c, self.physical_qubits) for c in self.circuits()]
382+
transpiled = minimal_transpile(circuits, self.backend, self.transpile_options)
379383

380384
return transpiled
381385

@@ -418,11 +422,36 @@ def set_experiment_options(self, **fields):
418422

419423
@classmethod
420424
def _default_transpile_options(cls) -> Options:
421-
"""Default transpiler options for transpilation of circuits"""
425+
"""Default transpiler options for transpilation of circuits
426+
427+
Transpile Options:
428+
optimization_level (int): Optimization level to pass to
429+
:func:`qiskit.transpile`.
430+
num_processes (int): Number of processes to use during
431+
transpilation on Qiskit >= 1.0.
432+
full_transpile (bool): If ``True``,
433+
``BaseExperiment._transpiled_circuits`` (called by
434+
:meth:`BaseExperiment.run` if not overridden by a subclass)
435+
will call :func:`qiskit.transpile` on the output of
436+
:meth:`BaseExperiment.circuits` before executing the circuits.
437+
If ``False``, ``BaseExperiment._transpiled_circuits`` will
438+
reindex the qubits in the output of
439+
:meth:`BaseExperiment.circuits` using the experiments'
440+
:meth:`BaseExperiment.physical_qubits`. Then it will check if
441+
the circuit operations are all defined in the
442+
:class:`qiskit.transpiler.Target` of the experiment's backend
443+
or in the indiivdual circuit calibrations. If not, it will use
444+
:class:`qiskit.transpiler.passes.BasisTranslator` to map the
445+
circuit instructions to the backend. Additionally,
446+
the :class:`qiskit.transpiler.passes.PulseGates` transpiler
447+
pass will be run if the :class:`qiskit.transpiler.Target`
448+
contains any custom pulse gate calibrations.
449+
450+
"""
422451
# Experiment subclasses can override this method if they need
423452
# to set specific default transpiler options to transpile the
424453
# experiment circuits.
425-
return Options(optimization_level=0)
454+
return copy.copy(DEFAULT_TRANSPILE_OPTIONS)
426455

427456
@property
428457
def transpile_options(self) -> Options:

qiskit_experiments/framework/experiment_data.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -866,11 +866,10 @@ def _add_job_data(
866866
LOG.warning("Job was cancelled before completion [Job ID: %s]", jid)
867867
return jid, False
868868
if status == JobStatus.ERROR:
869-
LOG.error(
870-
"Job data not added for errored job [Job ID: %s]\nError message: %s",
871-
jid,
872-
job.error_message(),
873-
)
869+
msg = f"Job data not added for errored job [Job ID: {jid}]"
870+
if hasattr(job, "error_message"):
871+
msg += f"\nError message: {job.error_message()}"
872+
LOG.error(msg)
874873
return jid, False
875874
LOG.warning("Adding data from job failed [Job ID: %s]", job.job_id())
876875
raise ex

0 commit comments

Comments
 (0)