Compilation et synthèse de circuits & Modèles alternatifs de calcul quantique
Comment un circuit idéal devient des portes exécutables (KAK, Solovay–Kitaev, routing) et pourquoi MBQC, adiabatique et topologique sont équivalents au modèle de circuit — sans prérequis mathématiques, avec du code Q# et Qiskit.
Compilation et synthèse de circuits
Comme en .NET un assembly IL est transformé par le JIT en instructions x64 propres à ta machine, un circuit quantique « idéal » doit être transpilé vers les portes physiques réellement disponibles sur le matériel cible, en respectant ses contraintes. Ce sont les mêmes idées qu’un compilateur classique : décomposer, approximer, optimiser, router.
1. Décomposition KAK (toute porte 2 qubits)
Toute porte agissant sur 2 qubits peut être réalisée avec au plus 3 CNOT (plus des rotations mono-qubit). C’est la décomposition KAK.
Analogie : n’importe quelle rotation 3D s’écrit avec 3 angles d’Euler. KAK est l’équivalent pour les opérations 2 qubits — une « forme normale » qui borne le coût. Comme les CNOT sont les portes les plus bruitées du matériel actuel, savoir qu’on n’en a jamais besoin de plus de 3 est un résultat central.
2. Solovay–Kitaev (approximer avec un jeu fini)
Une vraie machine n’offre qu’un jeu discret de portes (souvent Clifford+T). On ne peut pas réaliser un angle de rotation arbitraire exactement — il faut l’approcher.
Le théorème de Solovay–Kitaev garantit qu’on peut approximer n’importe quelle porte mono-qubit à une précision ε avec une séquence de longueur seulement polylogarithmique en 1/ε, soit O(logᶜ(1/ε)).
Intuition : doubler la précision ne coûte qu’une poignée de portes en plus, pas le double. C’est ce qui rend l’approximation viable en pratique.
Piège : T (et son adjoint T†) est la porte non-Clifford coûteuse. Le nombre de T dans le circuit — le « T-count » — est la vraie métrique de coût en calcul tolérant aux fautes, car chaque T exige un état magique distillé. Minimiser les CNOT et minimiser le T-count sont deux objectifs distincts.
3. Optimisation par patterns
- Annulation d’involutions :
H · H = I,X · X = I→ on supprime les paires adjacentes. - Fusion de rotations :
Rz(α) · Rz(β) = Rz(α+β). - Réécritures par identités de commutation pour rapprocher des portes annulables.
4. Qubit routing (la contrainte la plus dure en pratique)
Sur une vraie puce, les qubits forment un graphe de couplage : un CNOT n’est possible qu’entre qubits physiquement voisins. Le circuit logique, lui, suppose que tout qubit peut interagir avec tout autre.
Le routing insère des portes SWAP pour rapprocher les qubits non adjacents. Chaque SWAP coûte 3 CNOT — il gonfle donc profondeur et bruit. Trouver le placement et l’ordre de SWAP optimaux est NP-difficile ; les transpileurs utilisent des heuristiques.
| Étape de compilation | Rôle | Métrique de coût |
|---|---|---|
| KAK | Décomposer une porte 2 qubits | ≤ 3 CNOT |
| Solovay–Kitaev | Approximer avec un jeu discret | Longueur O(logᶜ(1/ε)) |
| Optimisation patterns | Simplifier les séquences | Profondeur, nb de portes |
| Routing (SWAP) | Respecter le graphe de couplage | 3 CNOT par SWAP |
| Tolérance aux fautes | Coût logique réel | T-count |
from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import GenericBackendV2
qc = QuantumCircuit(3)
qc.h(0)
qc.cx(0, 2) # qubits 0 et 2 : potentiellement NON voisins
qc.cx(1, 2)
# Cible : une puce en ligne 0-1-2 (0 et 2 ne sont PAS adjacents)
backend = GenericBackendV2(num_qubits=3, coupling_map=[[0, 1], [1, 2]])
# optimization_level 0 = traduction brute, 3 = optimisation maximale
tqc = transpile(qc, backend, optimization_level=3)
# Le transpileur a inséré des SWAP pour respecter le coupling_map,
# puis réécrit tout dans les portes natives (basis gates) du backend.
print(tqc.count_ops())
// En Q#, le compilateur SAIT synthétiser l'adjoint et la version contrôlée
// d'une opération marquée `is Adj + Ctl` — tu n'écris pas le circuit à la main.
operation AppliquerRotation(theta : Double, q : Qubit) : Unit is Adj + Ctl {
Ry(theta, q); // l'adjoint Ry(-theta) est dérivé automatiquement
}
operation Demo(q : Qubit, ctrl : Qubit) : Unit {
Adjoint AppliquerRotation(0.3, q); // applique Ry(-0.3)
Controlled AppliquerRotation([ctrl], (0.3, q)); // version contrôlée synthétisée
// Le back-end transpile ensuite ces opérations vers le jeu de portes natif.
}
Modèles alternatifs de calcul quantique
Le « modèle de circuit » (qubits + portes + mesure finale) n’est qu’une façon de calculer, comme la programmation impérative n’est qu’un paradigme parmi d’autres. Plusieurs autres modèles existent. Point capital : ils sont polynomialement équivalents en puissance — tout ce que l’un calcule efficacement, les autres aussi. Le choix relève de l’implémentation matérielle, pas du pouvoir de calcul.
1. Calcul par la mesure (MBQC / « one-way »)
On prépare d’abord un grand état intriqué générique (un cluster state), puis on calcule uniquement en mesurant les qubits un par un. Aucune porte à 2 qubits pendant le calcul.
- « One-way » (à sens unique) car la mesure est irréversible : on consomme l’état intriqué, on ne revient pas en arrière.
- Le calcul est dirigé par le choix de la base de mesure de chaque qubit.
- Les bases futures dépendent des résultats déjà obtenus → adaptativité (feed-forward) et besoin de communication classique rapide.
Analogie .NET : au lieu d’exécuter des instructions une à une, on alloue d’emblée une énorme structure pré-câblée, puis on « lit » des cases dans un ordre et une base choisis, chaque lecture orientant la suivante.
2. Calcul quantique adiabatique (AQC)
On encode la solution du problème dans l’état de plus basse énergie (le « ground state ») d’un hamiltonien final, et on y amène le système lentement depuis un état de départ facile à préparer.
Le théorème adiabatique dit : si on change le système assez lentement, il reste dans son état fondamental. La vitesse autorisée dépend du gap (écart d’énergie) minimal rencontré : plus le gap est petit, plus il faut aller lentement (temps ∝ 1/gap²).
À ne pas confondre : l’AQC idéal (universel, prouvé équivalent au modèle de circuit) ≠ le recuit quantique (« quantum annealing », type D-Wave), qui est une version restreinte et bruitée, spécialisée dans l’optimisation et non prouvée universelle.
3. Calcul quantique topologique
L’information est stockée dans des propriétés globales/topologiques (l’ordre dans lequel on tresse des quasi-particules appelées anyons), pas dans l’état local d’un qubit isolé.
Les portes sont réalisées en tressant (braiding) ces anyons les uns autour des autres. Avantage décisif : le résultat ne dépend que de la topologie de la tresse, pas de sa forme exacte. Une petite perturbation locale ne change pas la topologie → protection intrinsèque contre le bruit, une forme de correction d’erreur « câblée dans la physique ».
| Modèle | Ressource / mécanisme | Particularité |
|---|---|---|
| Circuit | Portes appliquées dans le temps | Le modèle « par défaut » |
| MBQC (one-way) | Cluster state + mesures adaptatives | Intrication d’abord, calcul = mesures |
| Adiabatique (AQC) | Évolution lente vers le ground state | Universel ; vitesse ∝ 1/gap² |
| Recuit (annealing) | AQC restreint et bruité | Optimisation ; non prouvé universel |
| Topologique | Tressage d’anyons | Protection contre le bruit par topologie |
À retenir absolument : tous ces modèles (sauf le recuit restreint) sont équivalents en puissance au modèle de circuit, à un facteur polynomial près. On peut toujours traduire l’un dans l’autre efficacement.
from qiskit import QuantumCircuit
# On prépare l'intrication AVANT, puis le "calcul" se fait par la mesure.
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1) # petite ressource intriquée préparée d'emblée
qc.measure(0, 0) # mesurer q0 fixe une corrélation et influence q1
# En MBQC complet : la BASE de la mesure suivante dépendrait de ce résultat (feed-forward).
qc.measure(1, 1)