Set the optimization level
Decomposing quantum circuits into the basis gate set of the target device and the addition of SWAP gates needed to match hardware topology causes an increase in the depth and gate count of quantum circuits. To mitigate this increased complexity, you can set the optimization_level
. Setting this value calls an optimization routine that optimizes the transpilation process by combining or eliminating gates and by optionally using algorithms to find an optimal layout (depending on the level chosen).
In some cases these methods are so effective the output circuits have lower depth than the inputs. In other cases, not much can be done, and the computation may be difficult to perform on noisy devices. Choosing the best optimization level might take trial and error, as it depends heavily on the circuit being transpiled and the system being targeted.
Higher optimization levels generate more optimized circuits at the expense of longer compile times. By default, optimization_level=1
is used.
optimization_level=0
: Trivial optimization, which maps the circuit to the system with no explicit optimization.optimization_level=13
: Increasingly complex optimization, with heuristic algorithms that are used to find a layout and insert SWAP gates, with the goal of improving the overall performance of the circuit. The number of iterations that these algorithms run increases with higher optimization levels.
Because finding the best layout is an NPhard problem, it is the most timeconsuming part of the transpilation process. However, Qiskit® uses stochastic algorithms that have been refactored into Rust, resulting in significant speedup. Therefore, optimization levels 13 all use the same layout algorithms. There are some slight differences in how the circuits are translated into basis gates, as described in the following table:
Optimization Level  Description 

0  No optimization: typically used for hardware characterization

1  Light optimization (default):

2  Medium optimization:

3  High Optimization:

Optimization level in action
Since CX is the noisiest gate, we can quantify the transpilation's "hardware efficiency" by counting the CX gates in the resulting circuit. We will compare the default transpilation levels given the same circuit.
First, import the necessary libraries:
from qiskit import transpile, QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.providers.fake_provider import FakeTokyo
from qiskit.quantum_info import Operator, random_unitary
from qiskit.quantum_info.synthesis.two_qubit_decompose import trace_to_fid
import numpy as np
Next we build a quantum circuit consisting of a random unitary followed by a SWAP gate. The random_unitary
method is seeded to ensure reproducible results.
UU = random_unitary(4, seed=12345)
rand_U = UnitaryGate(UU)
qc = QuantumCircuit(2)
qc.append(rand_U, range(2))
qc.swap(0, 1)
qc.draw('mpl', style="iqp")
We use FakeTokyo
as the system and transpile using optimization_level=1
(the default). To avoid considering the effect of idle qubits, We override the system's coupling map so that the transpiled circuit returns to a twoqubit circuit.
backend = FakeTokyo()
qc_t1_exact = transpile(qc, backend, optimization_level=1, coupling_map=[[0, 1], [1, 0]], seed_transpiler=12345)
qc_t1_exact.draw('mpl', style='iqp')
The transpiled circuit has six CX gates and several U3
gates, which have much lower error than CX's, so we don't need to count them.
Repeat for optimization level 2:
qc_t2_exact = transpile(qc, backend, optimization_level=2, coupling_map=[[0, 1], [1, 0]], seed_transpiler=12345)
qc_t2_exact.draw('mpl', style='iqp')
This yields the same results as optimization level 1. Note that increasing the level of optimization does not always make a difference.
Repeat again, with optimization level 3:
qc_t3_exact = transpile(qc, backend, optimization_level=3, coupling_map=[[0, 1], [1, 0]], seed_transpiler=12345)
qc_t3_exact.draw('mpl', style='iqp')
Now there are only three CX gates. This is because with optimization level 3, Qiskit tries to resynthesize twoqubit blocks of gates. Since any twoqubit gate requires at most three CX gates, we get the above result. We can get even fewer CX gates if we sacrifice the fidelity of this synthese by setting approximation_degree
to a value less than 1:
qc_t3_approx = transpile(qc, backend, optimization_level=3, approximation_degree=0.99, coupling_map=[[0, 1], [1, 0]], seed_transpiler=12345)
qc_t3_approx.draw('mpl', style='iqp')
This circuit has only two CX gates. However, this is an approximate circuit, so we need to understand the difference in fidelity to the desired circuit with the incurred error from running on noisy qubits. We can calculate the fidelity of the approximate circuit:
exact_fid = trace_to_fid(np.trace(np.dot(Operator(qc_t3_exact).adjoint().data, UU)))
approx_fid = trace_to_fid(np.trace(np.dot(Operator(qc_t3_approx).adjoint().data, UU)))
print(f'Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}')
Synthesis fidelity
Exact: 1.000
Approximate: 0.992
Adjusting the optimization level can change other aspects of the circuit too, not just the number of CX gates. For examples of how setting optimization level changes the layout, see Representing quantum computers.
Next steps
 To learn how to use the
transpile
function, start with the Transpilation default settings and configuration options topic.  Continue learning about transpilation with the Transpiler stages topic.
 Try the Submit transpiled circuits(opens in a new tab) tutorial.
 Try the Build repetition codes(opens in a new tab) tutorial.
 See the Transpile API documentation.