To construct an equivalent circuit that can run on a specific system, the transpiler needs certain details about the system. Typically, this information is found in the
target = backend.target class, so you don't need to pass anything further to the transpiler. However, if more information is provided, the transpiler can use it to try to produce the best circuit to run on that hardware.
Because many of the underlying transpilation algorithms are stochastic, there is no guarantee that a better circuit will be found.
The simplest use of the transpiler is to provide all the system information by providing the
target. To better understand how the transpiler works, construct a circuit and transpile it with different information:
Import the necessary libraries and instantiate the system or simulator:
from qiskit import transpile
from qiskit.circuit.library import EfficientSU2
from qiskit.providers.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
target = backend.target
EfficientSU2 circuit consists of layers of single-qubit operations spanned by
CX entanglements. This is a heuristic pattern that can be used to prepare trial wave functions for variational quantum algorithms or classification circuits for machine learning.
qc = EfficientSU2(12, entanglement='circular', reps=1)
This example uses the default
optimization_level=1 to transpile to the
target, which providers all the information to the transpiler that is necessary to convert circuit to one that will run on the system.
qc_t_target = transpile(qc, target=target, seed_transpiler=12345)
qc_t_target.draw('mpl', style='iqp', idle_wires=False)
This example is used in later sections of this topic to illustrate that the coupling map and basis gates are the essential pieces of information to pass to the transpiler for optimal circuit construction. The system can usually select default settings for other information that is not passed in, such as timing and scheduling.
backend properties, including the gates' error rates, allows the transpiler to select the best set of qubits on the system.
The coupling map is a graph that shows which qubits are connected and hence have two-qubit gates between them. Sometimes this graph is directional, meaning that the two-qubit gates can only go in one direction. However, the transpiler can always flip a gate's direction by adding additional single-qubit gates. An abstract quantum circuit can always be represented on this graph, even if its connectivity is limited, by introducing SWAP gates to move the quantum information around.
The qubits from our abstract circuits are called virtual qubits and those on the coupling map are physical qubits. The transpiler provides a mapping between virtual and physical qubits. One of the first steps in transpilation, the routing stage, performs this mapping.
Although the routing stage is intertwined with the layout stage, which selects the actual qubits, we will consider them as separate stages for simplicity. The combination of routing and layout is called qubit mapping. Learn more about these stages in the Transpiler stages topic.
coupling_map keyword argument to see its effect on the transpiler:
coupling_map = target.build_coupling_map()
qc_t_cm_lv0 = transpile(qc, coupling_map=coupling_map, optimization_level=0, seed_transpiler=11)
qc_t_cm_lv0.draw('mpl', style='iqp', idle_wires=False)
As shown above, several SWAP gates were inserted (each consisting of three CX gates), which will cause a lot of errors on current devices. To see which qubits are selected on the actual qubit topology, use
plot_circuit_layout from Qiskit® Visualizations:
from qiskit.visualization import plot_circuit_layout
plot_circuit_layout(qc_t_cm_lv0, backend, view='physical')
This shows that our virtual qubits 0-11 were trivially mapped to the line of physical qubits 0-11. Let's return to the default (
optimization_level=1), which uses
VF2Layout if any routing is required.
qc_t_cm_lv1 = transpile(qc, coupling_map=coupling_map, seed_transpiler=11)
qc_t_cm_lv1.draw('mpl', style='iqp', idle_wires=False)
Now there are no SWAP gates inserted and the physical qubits selected are the same when using the
from qiskit.visualization import plot_circuit_layout
plot_circuit_layout(qc_t_cm_lv1, backend, view='physical')
Now the layout is in a ring. Because this layout respects the circuit's connectivity, there are no SWAP gates, providing a much better circuit for execution.
Every quantum system supports a limited instruction set, called its basis gates. Every gate in the circuit must be translated to the elements of this set. This set should consist of single- and two-qubit gates that provide a universal gates set, meaning that any quantum operation can be decomposed into those gates. This is done by the BasisTranslator, and the basis gates can be specified as a keyword argument to the transpiler to provide this information.
basis_gates = list(target.operation_names)
['rz', 'sx', 'x', 'ecr', 'measure', 'delay']
The default single-qubit gates on ibm_sherbrooke are
sx, and the default two-qubit gate is
ecr (echoed cross-resonance). CX gates are constructed from
ecr gates, so on some systems
ecr is specified as the two-qubit basis gate, while on others
cx is default. The
ecr gate is the entangling part of the
cx gate. To use a gate that is not in the basis gate set, follow instructions in the Qiskit API documentation for custom gates using pulse gates. In addition to the control gates, there are also
Systems have default basis gates, but you can choose whatever gates you want, as long as you provide the instruction or add pulse gates (see Create transpiler passes.) The default basis gates are those that calibrations have been done for on the system, so no further instruction/pulse gate needs to be provided. For example, on some systems
cx is the default two-qubit gate and
ecr on others. See the Native gates and operations topic for more details.
qc_t_cm_bg = transpile(qc, coupling_map=coupling_map, basis_gates=basis_gates, seed_transpiler=11)
qc_t_cm_bg.draw('mpl', style='iqp', fold=-1, idle_wires=False)
Note that the
CXGates have been decomposed to
ecr gates and single-qubit basis gates.
target object lets you consider the qubits' error rates in addition to the
target object contains everything needed to target a system, but here we build one that contains a limited amount of information.
We retrieved the
backend.target previously. This contains a lot of system information, including error rates. For example, the instruction properties of the echoed cross-resonance gate between qubit 0 and 1 (note that
ecr is directional) is retrieved by running the following command:
InstructionProperties(duration=5.333333333333332e-07, error=0.006969730734746021, calibration=PulseQobj)
The above result shows that the gate is 533μs with an error of 0.7%. To reveal error information to the transpiler, we will build our own target model with the
coupling_map from above and populate it with error values from the backend
from qiskit.transpiler import Target
err_targ = Target.from_configuration(basis_gates=basis_gates, coupling_map=coupling_map, num_qubits=target.num_qubits)
for idx in range(len(target.instructions)):
err_targ[target.instructions[idx].name][target.instructions[idx]] = target.instruction_properties(idx)
Transpile with our new target
err_targ as the target:
qc_t_cm_bg_et = transpile(qc, target=err_targ, seed_transpiler=11)
qc_t_cm_bg_et.draw('mpl', style='iqp', fold=-1, idle_wires=False)
Note that by including the error information, the
VF2PostLayout pass tries to find the optimal qubits to use, resulting in the same circuit that we found originally with the same physical qubits.
- Understand Transpilation default settings and configuration options.
- Review the Commonly used parameters for transpilation topic.
- Try the Submit transpiled circuits(opens in a new tab) tutorial.
- See the Transpile API documentation.