Portes contrôlées et CNOT & Lecture de circuits quantiques
Portes contrôlées (CNOT, CZ, Toffoli) et lecture de circuits quantiques — sans prérequis mathématiques, avec du code Q# et Qiskit.
Portes contrôlées et CNOT
L’idée clé : un qubit qui commande un autre
Une porte contrôlée, c’est comme un if en programmation : « si le qubit de contrôle est dans l’état |1⟩, alors applique telle opération sur le qubit cible ; sinon, ne fais rien. »
- Le qubit de contrôle n’est pas modifié par l’opération — il conditionne ce qui arrive au qubit cible.
- En superposition, le contrôle peut être
|0⟩et|1⟩« en même temps » — la porte agit de façon conditionnelle sur chaque branche. C’est ce qui crée l’intrication.
La porte CNOT (Controlled-NOT)
La CNOT fait un bit-flip (X) sur la cible si et seulement si le contrôle vaut |1⟩. Autrement dit, un XOR : cible = cible ⊕ contrôle.
|00⟩ → |00⟩— contrôle = 0, rien ne change|01⟩ → |01⟩— contrôle = 0, rien ne change|10⟩ → |11⟩— contrôle = 1, la cible flip de 0 à 1|11⟩ → |10⟩— contrôle = 1, la cible flip de 1 à 0
La porte CZ (Controlled-Z)
La CZ applique un Z (changement de phase) à la cible si le contrôle est |1⟩. Elle multiplie par −1 uniquement l’amplitude de |11⟩.
Point important : La CZ est symétrique — peu importe lequel des deux qubits est le contrôle ou la cible, le résultat est identique. Ce n’est pas le cas de la CNOT !
La porte Toffoli (CCX)
La Toffoli a deux qubits de contrôle et un qubit cible. Elle fait un X sur la cible uniquement si les deux contrôles sont |1⟩. Pensez à un if (a && b) en C#.
La Toffoli est universelle pour le calcul classique : tout circuit booléen peut être construit avec des Toffoli. C’est le pont entre le monde classique et quantique.
Tableau récapitulatif
| Porte | Contrôle(s) | Action sur cible | Q# | Qiskit |
|---|---|---|---|---|
| CNOT | 1 qubit | X (bit-flip) | CNOT(ctrl, tgt) | qc.cx(ctrl, tgt) |
| CZ | 1 qubit | Z (phase-flip) | CZ(ctrl, tgt) | qc.cz(ctrl, tgt) |
| Toffoli | 2 qubits | X (bit-flip) | CCNOT(c1, c2, tgt) | qc.ccx(c1, c2, tgt) |
Exemple Q# — créer un état de Bell avec CNOT
// Q# : créer l'état de Bell |Φ+⟩ = (|00⟩ + |11⟩) / √2
operation CreateBellPair() : (Result, Result) {
use (ctrl, tgt) = (Qubit(), Qubit());
H(ctrl); // met ctrl en superposition |+⟩
CNOT(ctrl, tgt); // intrication : si ctrl=|1⟩, flip tgt
// État résultant : (|00⟩ + |11⟩) / √2
let r1 = M(ctrl);
let r2 = M(tgt);
Reset(ctrl);
Reset(tgt);
return (r1, r2); // toujours corrélés : 00 ou 11
}
Exemple Qiskit — Toffoli et mesure
# Qiskit : Toffoli — flip cible seulement si les 2 contrôles = |1⟩
from qiskit import QuantumCircuit
qc = QuantumCircuit(3, 1)
qc.x(0) # met q0 = |1⟩
qc.x(1) # met q1 = |1⟩
qc.ccx(0, 1, 2) # Toffoli : q2 flip car q0=q1=|1⟩
qc.measure(2, 0)
# Résultat : q2 = |1⟩ avec 100% de probabilité
⚠️ Piège courant : L’ordre des arguments compte ! En Qiskit,
qc.cx(0, 1)signifie « q0 contrôle, q1 cible ». Si vous inversez, le circuit fait tout autre chose.
Lecture de circuits quantiques
Un circuit quantique, c’est du code visuel
- Un circuit se lit de gauche à droite — comme du code qui s’exécute séquentiellement. Chaque colonne verticale représente un instant.
- Chaque ligne horizontale (fil) représente un qubit. Le fil du haut est souvent q0.
- La mesure est toujours en fin de circuit. Après la mesure, le qubit est « classique ».
Conventions graphiques essentielles
| Symbole | Signification |
|---|---|
| Boîte avec lettre (H, X, Z…) | Porte mono-qubit sur ce fil |
| ● relié à ⊕ | CNOT : ● = contrôle, ⊕ = cible |
| ● relié à ● | CZ : symétrique |
| ●●⊕ | Toffoli : 2 contrôles + 1 cible |
| Compteur / double trait | Mesure dans la base computationnelle |
| Trait en pointillé (barrier) | Séparateur visuel (aucun effet physique) |
Lire un circuit étape par étape
Prenons le circuit de Bell :
- Étape 1 : Tous les qubits démarrent à
|0⟩. - Étape 2 : H sur q0 → superposition
(|0⟩+|1⟩)/√2. - Étape 3 : CNOT(q0, q1) → intrication
(|00⟩+|11⟩)/√2. - Étape 4 : Mesure → 00 ou 11, chacun à 50%.
Équivalence circuit ↔ code
Chaque porte du circuit correspond à une ligne de code. L’ordre de lecture (gauche → droite) = l’ordre d’exécution.
# Qiskit : le circuit de Bell lu « visuellement »
from qiskit import QuantumCircuit
qc = QuantumCircuit(2, 2) # 2 qubits, 2 bits classiques
qc.h(0) # colonne 1 : H sur q0
qc.cx(0, 1) # colonne 2 : CNOT ctrl=q0, tgt=q1
qc.measure([0, 1], [0, 1]) # colonne 3 : mesure
print(qc.draw())
// Q# : même circuit
operation BellCircuit() : (Result, Result) {
use (q0, q1) = (Qubit(), Qubit());
H(q0); // étape 1 du circuit
CNOT(q0, q1); // étape 2
let r0 = M(q0); // étape 3
let r1 = M(q1);
Reset(q0); Reset(q1);
return (r0, r1);
}
Déboguer par simulation
- En Qiskit,
Aer.get_backend('statevector_simulator')permet de voir le vecteur d’état exact après chaque porte — l’équivalent d’un breakpoint avec « watch ». - En Q#,
DumpMachine()affiche l’état complet du registre quantique. Pensez-y comme unConsole.WriteLine()pour qubits.
⚠️ Piège courant : L’ordre des qubits dans Qiskit est little-endian (q0 = bit de poids faible, en bas du circuit dessiné). Vérifiez toujours avec
qc.draw()et comparez avec les résultats de mesure.