Définir le niveau d'optimisation du transpileur
Versions des packages
Le code de cette page a été développé avec les dépendances suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Les appareils quantiques réels sont soumis au bruit et aux erreurs de portes, c'est pourquoi optimiser les circuits pour réduire leur profondeur et leur nombre de portes peut améliorer significativement les résultats obtenus lors de l'exécution de ces circuits.
La fonction generate_preset_pass_manager possède un argument positionnel obligatoire, optimization_level, qui contrôle l'effort que le transpileur consacre à l'optimisation des circuits. Cet argument est un entier pouvant prendre les valeurs 0, 1, 2 ou 3.
Plus le niveau d'optimisation est élevé, plus les circuits générés sont optimisés, au prix de temps de compilation plus longs.
Le tableau suivant décrit les optimisations effectuées pour chaque valeur.
| Niveau d'optimisation | Description |
|---|---|
| 0 | Aucune optimisation : généralement utilisé pour la caractérisation matérielle
|
| 1 | Optimisation légère :
|
| 2 | Optimisation moyenne :
|
| 3 | Optimisation élevée :
|
Le niveau d'optimisation en pratique
Les portes à deux qubits étant généralement la principale source d'erreurs, on peut quantifier approximativement l'« efficacité matérielle » de la transpilation en comptant le nombre de portes à deux qubits dans le circuit résultant. Ici, nous allons essayer les différents niveaux d'optimisation sur un circuit d'entrée composé d'une unitaire aléatoire suivie d'une porte SWAP.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.quantum_info import Operator, random_unitary
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")
Nous utiliserons le backend simulé FakeSherbrooke dans nos exemples. Commençons par transpiler avec le niveau d'optimisation 0.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
pass_manager = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)
Le circuit transpilé comporte six portes ECR à deux qubits.
Recommençons avec le niveau d'optimisation 1 :
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend = FakeSherbrooke()
pass_manager = generate_preset_pass_manager(
optimization_level=1, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)
Le circuit transpilé contient toujours six portes ECR, mais le nombre de portes à un qubit a diminué.
Recommençons avec le niveau d'optimisation 2 :
pass_manager = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=12345
)
qc_t2_exact = pass_manager.run(qc)
qc_t2_exact.draw("mpl", idle_wires=False)
On obtient les mêmes résultats qu'avec le niveau d'optimisation 1. À noter qu'augmenter le niveau d'optimisation ne fait pas toujours une différence.
Recommençons, cette fois avec le niveau d'optimisation 3 :
pass_manager = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=12345
)
qc_t3_exact = pass_manager.run(qc)
qc_t3_exact.draw("mpl", idle_wires=False)
Cette fois, il n'y a plus que trois portes ECR. Ce résultat s'explique par le fait qu'au niveau d'optimisation 3, Qiskit tente de resynthétiser les blocs de portes à deux qubits, et toute porte à deux qubits peut être implémentée avec au plus trois portes ECR. On peut obtenir encore moins de portes ECR en fixant approximation_degree à une valeur inférieure à 1, ce qui permet au transpileur de faire des approximations pouvant introduire une légère erreur dans la décomposition des portes (voir Paramètres couramment utilisés pour la transpilation) :
pass_manager = generate_preset_pass_manager(
optimization_level=3,
approximation_degree=0.99,
backend=backend,
seed_transpiler=12345,
)
qc_t3_approx = pass_manager.run(qc)
qc_t3_approx.draw("mpl", idle_wires=False)
Ce circuit ne comporte que deux portes ECR, mais il s'agit d'un circuit approximatif. Pour comprendre en quoi son effet diffère du circuit exact, on peut calculer la fidélité entre l'opérateur unitaire implémenté par ce circuit et l'unitaire exact. Avant d'effectuer le calcul, on réduit d'abord le circuit transpilé, qui contient 127 qubits, à un circuit ne contenant que les qubits actifs, soit deux.
import numpy as np
def trace_to_fidelity_2q(trace: float) -> float:
return (4.0 + trace * trace.conjugate()) / 20.0
# Reduce circuits down to 2 qubits so they are easy to simulate
qc_t3_exact_small = QuantumCircuit.from_instructions(qc_t3_exact)
qc_t3_approx_small = QuantumCircuit.from_instructions(qc_t3_approx)
# Compute the fidelity
exact_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_exact_small).adjoint().data, UU))
)
approx_fid = trace_to_fidelity_2q(
np.trace(np.dot(Operator(qc_t3_approx_small).adjoint().data, UU))
)
print(
f"Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}"
)
Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j
Ajuster le niveau d'optimisation peut modifier d'autres aspects du circuit, pas seulement le nombre de portes ECR. Pour des exemples illustrant comment le niveau d'optimisation influe sur le layout, consulte Représenter les ordinateurs quantiques.
Prochaines étapes
- Pour en savoir plus sur la fonction
generate_preset_passmanager, commence par le sujet Paramètres par défaut et options de configuration de la transpilation. - Continue d'apprendre sur la transpilation avec le sujet Étapes du transpileur.
- Essaie le guide Comparer les paramètres du transpileur.
- Essaie le tutoriel Construire des codes de répétition.
- Consulte la documentation de l'API Transpile.