qiskit/releasenotes/notes/0.19/two-step-transpile-f20d709a...

67 lines
3.2 KiB
YAML

---
features:
- |
Allow two transpiler stages in the :class:`~qiskit.utils.QuantumInstance`, one for
parameterized circuits and a second one for bound circuits (i.e. no free parameters) only.
If a quantum instance with passes for unbound and bound circuits is passed into a
:class:`.CircuitSampler`, the sampler will attempt to apply the unbound pass
once on the parameterized circuit, cache it, and only apply the bound pass for all future
evaluations.
This enables variational algorithms like the :class:`~qiskit.algorithms.VQE` to run a
custom pass manager for parameterized circuits once and, additionally, another the transpiler
again with a different custom pass manager on the bound circuits in each iteration. Being able
to run different pass managers is important because not all passes support parameterized
circuits (for example :class:`~qiskit.transpiler.passes.Optimize1qGatesDecomposition` only
works with bound circuit parameters).
For example, this feature allows using the pulse-efficient CX decomposition in the VQE, as
.. code-block:: python
from qiskit.algorithms import VQE
from qiskit.opflow import Z
from qiskit.circuit.library.standard_gates.equivalence_library import StandardEquivalenceLibrary as std_eqlib
from qiskit.transpiler import PassManager, PassManagerConfig, CouplingMap
from qiskit.transpiler.preset_passmanagers import level_1_pass_manager
from qiskit.transpiler.passes import (
Collect2qBlocks, ConsolidateBlocks, Optimize1qGatesDecomposition,
RZXCalibrationBuilderNoEcho, UnrollCustomDefinitions, BasisTranslator
)
from qiskit.transpiler.passes.optimization.echo_rzx_weyl_decomposition import EchoRZXWeylDecomposition
from qiskit.test.mock import FakeBelem
from qiskit.utils import QuantumInstance
# Replace by a real backend! If not ensure qiskit-aer is installed to simulate the backend
backend = FakeBelem()
# Build the pass manager for the parameterized circuit
rzx_basis = ['rzx', 'rz', 'x', 'sx']
coupling_map = CouplingMap(backend.configuration().coupling_map)
config = PassManagerConfig(basis_gates=rzx_basis, coupling_map=coupling_map)
pre = level_1_pass_manager(config)
# Build a pass manager for the CX decomposition (works only on bound circuits)
post = PassManager([
# Consolidate consecutive two-qubit operations.
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=['rz', 'sx', 'x', 'rxx']),
# Rewrite circuit in terms of Weyl-decomposed echoed RZX gates.
EchoRZXWeylDecomposition(backend),
# Attach scaled CR pulse schedules to the RZX gates.
RZXCalibrationBuilderNoEcho(backend),
# Simplify single-qubit gates.
UnrollCustomDefinitions(std_eqlib, rzx_basis),
BasisTranslator(std_eqlib, rzx_basis),
Optimize1qGatesDecomposition(rzx_basis),
])
quantum_instance = QuantumInstance(backend, pass_manager=pre, bound_pass_manager=post)
vqe = VQE(quantum_instance=quantum_instance)
result = vqe.compute_minimum_eigenvalue(Z ^ Z)