Kvantové brány a obvody: Od NOT a CNOT k algoritmům s Qiskit
Pokud je qubit informační jednotkou kvantového počítání, kvantové brány jsou to operace, které jej transformují – ekvivalent klasických booleovských operátorů. Ale na rozdíl od klasického AND, OR a NOT jsou kvantová hradla vždy reverzibilní a pracují na amplitudách stavových vektorů, nikoli na deterministických binárních hodnotách.
V tomto článku budujeme pochopení hlavních bran — Hadamard, X, Z, CNOT, SWAP – a používáme je k vytvoření prvního skutečného kvantového algoritmu: Bellova stavu, který demonstruje zapletení. Poté spustíme obvod na skutečném hardwaru IBM prostřednictvím IBM Quantum Platforma.
Co se naučíte
- 1-qubitová hradla: Hadamard (H), X (NOT), Z, S, T a jejich matice
- 2-qubitové brány: CNOT, CZ, SWAP a Toffoli
- Sestavte obvody pomocí Qiskit QuantumCircuit
- Bell State: Základní obvod, který demonstruje zapletení
- Simulace s Qiskit Aer a vizualizace výsledků
- Běží na skutečném hardwaru IBM se Sampler Primitive
- Transpilace: z logického obvodu do nativních hardwarových hradel
1 Qubit Gates: State Vector Transformations
1-qubitové hradlo a jednotková matice 2x2 (U^† U = I), která transformuje stavový vektor. Unitarita zaručuje reverzibilitu — operaci můžete vždy „vrátit zpět“ použitím přidány dveře.
# Porte a 1 qubit: definizione matematica e Qiskit
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator, Statevector
# Gate X (Pauli-X) — il NOT quantistico
# Matrice: [[0, 1], [1, 0]]
# Effetto: |0⟩ -> |1⟩, |1⟩ -> |0⟩
print("Gate X (NOT):")
print(Operator.from_label('X').data)
qc_x = QuantumCircuit(1)
qc_x.x(0)
print(f"X|0⟩ = {Statevector.from_instruction(qc_x).data}")
# [0.+0.j, 1.+0.j] = |1⟩
# Gate Hadamard (H) — crea superposizione
# Matrice: [[1/√2, 1/√2], [1/√2, -1/√2]]
# Effetto: |0⟩ -> |+⟩, |1⟩ -> |−⟩
print("\nGate H (Hadamard):")
qc_h = QuantumCircuit(1)
qc_h.h(0)
print(f"H|0⟩ = {Statevector.from_instruction(qc_h).data}")
# [0.707+0.j, 0.707+0.j] = |+⟩ = (|0⟩+|1⟩)/√2
# Gate Z (Pauli-Z) — phase flip
# Matrice: [[1, 0], [0, -1]]
# Effetto: |0⟩ -> |0⟩, |1⟩ -> -|1⟩ (cambia la fase di |1⟩)
print("\nGate Z (Phase Flip):")
print(f"Z|+⟩ = ?")
qc_z = QuantumCircuit(1)
qc_z.h(0) # prima crea |+⟩
qc_z.z(0) # poi applica Z
print(f"Z|+⟩ = {Statevector.from_instruction(qc_z).data}")
# [0.707+0.j, -0.707+0.j] = |−⟩
# Gate S e T — rotazioni di fase piu fini
# S = [[1,0],[0,i]]: rotazione di π/2 attorno asse Z
# T = [[1,0],[0,e^{iπ/4}]]: rotazione di π/4 attorno asse Z
qc_st = QuantumCircuit(1)
qc_st.h(0)
qc_st.s(0)
qc_st.t(0)
print(f"\nT(S|+⟩) = {Statevector.from_instruction(qc_st).data}")
2 Qubit brány: CNOT, CZ a SWAP
2-qubitové brány fungují na párech qubitů a jsou nezbytné k vytvoření zapletení. Nejdůležitější je CNOT (Kontrolováno-NE):
# Porte a 2 qubit
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
# CNOT (CX): se qubit control e |1⟩, flip il qubit target
# Matrice 4x4: [[1,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]]
print("CNOT truth table:")
for control_state, target_state in [(0,0), (0,1), (1,0), (1,1)]:
qc = QuantumCircuit(2)
if control_state == 1:
qc.x(0)
if target_state == 1:
qc.x(1)
qc.cx(0, 1) # qubit 0 = control, qubit 1 = target
sv = Statevector.from_instruction(qc)
result_probs = sv.probabilities_dict()
result = max(result_probs, key=result_probs.get)
print(f" CNOT|{control_state}{target_state}⟩ = |{result}⟩")
# CNOT|00⟩ = |00⟩
# CNOT|01⟩ = |01⟩
# CNOT|10⟩ = |11⟩ <- target si inverte quando control e 1
# CNOT|11⟩ = |10⟩ <- target si inverte quando control e 1
# SWAP: scambia gli stati dei due qubit
qc_swap = QuantumCircuit(2)
qc_swap.x(0) # qubit 0 = |1⟩, qubit 1 = |0⟩
qc_swap.swap(0, 1)
sv_swap = Statevector.from_instruction(qc_swap)
print(f"\nSWAP|10⟩ = {max(sv_swap.probabilities_dict(), key=sv_swap.probabilities_dict().get)}")
# SWAP|10⟩ = |01⟩
# Toffoli (CCX): CNOT con 2 qubit di controllo
# Il gate universale per computazione classica reversibile
qc_toffoli = QuantumCircuit(3)
qc_toffoli.x(0) # control 1 = |1⟩
qc_toffoli.x(1) # control 2 = |1⟩
qc_toffoli.ccx(0, 1, 2) # flip target solo se entrambi i control sono |1⟩
sv_t = Statevector.from_instruction(qc_toffoli)
print(f"Toffoli|110⟩ = {max(sv_t.probabilities_dict(), key=sv_t.probabilities_dict().get)}")
# Toffoli|110⟩ = |111⟩
The Bell State: First Complete Circuit
Bellův stav je nejjednodušší obvod, který demonstruje skutečné zapletení. To pouze vyžaduje dvě brány – Hadamard a CNOT – a je základem mnoha kvantových algoritmů:
# Bell State: costruzione, simulazione e analisi
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, DensityMatrix
from qiskit_aer import AerSimulator
from qiskit import transpile
# Costruzione del circuito Bell State |Φ+⟩
qc_bell = QuantumCircuit(2, 2, name='Bell State')
# Passo 1: Hadamard su qubit 0
# Stato: (|00⟩ + |10⟩) / √2
qc_bell.h(0)
# Passo 2: CNOT con qubit 0 come control, qubit 1 come target
# Stato: (|00⟩ + |11⟩) / √2 <- Bell state!
qc_bell.cx(0, 1)
# Visualizza il circuito
print("Circuito Bell State:")
print(qc_bell.draw('text'))
print()
# Analisi statevector (senza misura)
sv = Statevector.from_instruction(qc_bell)
print(f"Statevector: {sv.data}")
# [0.707, 0, 0, 0.707] -> 50% |00⟩, 50% |11⟩
print(f"Probabilita: {sv.probabilities_dict()}")
# {'00': 0.5, '11': 0.5} <- nessuna probabilita per '01' e '10'
# Aggiungi misura e simula
qc_bell.measure([0, 1], [0, 1])
sim = AerSimulator()
compiled = transpile(qc_bell, sim)
result = sim.run(compiled, shots=10000).result()
counts = result.get_counts()
print(f"\nRisultati simulazione (10000 shots): {counts}")
# {'00': ~5000, '11': ~5000} — MAI '01' o '10'
# Verifica entanglement: calcola concurrence
dm = DensityMatrix.from_instruction(QuantumCircuit(2).compose(
QuantumCircuit(2).compose(QuantumCircuit(2))
))
# (entanglement misurabile con partial trace e reduced density matrix)
4 Bellovy státy
Existují 4 Bellovy stavy — základ 4-rozměrného Hilbertova prostoru o 2 qubitech:
# Tutti e 4 i Bell States
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
def create_bell_state(phi_plus=True, psi=False) -> QuantumCircuit:
"""
|Φ+⟩ = (|00⟩ + |11⟩)/√2 (phi_plus=True, psi=False)
|Φ-⟩ = (|00⟩ - |11⟩)/√2 (phi_plus=False, psi=False)
|Ψ+⟩ = (|01⟩ + |10⟩)/√2 (phi_plus=True, psi=True)
|Ψ-⟩ = (|01⟩ - |10⟩)/√2 (phi_plus=False, psi=True)
"""
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
if psi:
qc.x(1) # Flip target: |00⟩ e |11⟩ diventano |01⟩ e |10⟩
if not phi_plus:
qc.z(0) # Phase flip: + diventa -
return qc
bell_states = {
'|Φ+⟩': create_bell_state(True, False),
'|Φ-⟩': create_bell_state(False, False),
'|Ψ+⟩': create_bell_state(True, True),
'|Ψ-⟩': create_bell_state(False, True),
}
for name, qc in bell_states.items():
sv = Statevector.from_instruction(qc)
probs = {k: round(v, 3) for k, v in sv.probabilities_dict().items() if v > 0.01}
print(f"{name}: probabilita = {probs}")
Běží na skutečném hardwaru IBM
Simulovat a užitečné pro vývoj, ale skutečný test a fyzický hardware. Zde je pracovní postup kompletní s Qiskit v2 pro spuštění stavu Bell na skutečném procesoru IBM:
# Esecuzione su hardware IBM reale con Qiskit v2 Primitives
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
# Autenticazione
service = QiskitRuntimeService(channel='ibm_quantum')
# Seleziona il backend meno occupato (per account gratuito)
backend = service.least_busy(
operational=True,
simulator=False,
min_num_qubits=2
)
print(f"Backend: {backend.name}")
print(f"Qubit disponibili: {backend.num_qubits}")
print(f"Job in coda: {backend.status().pending_jobs}")
# Crea il circuito Bell State
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
# NUOVO in Qiskit v2: transpile ottimizzato per l'hardware specifico
# 83x piu veloce rispetto a Qiskit 0.x per circuiti complessi
pass_manager = generate_preset_pass_manager(
backend=backend,
optimization_level=1 # 0=veloce, 1=bilanciato, 2=lento ma ottimale
)
isa_circuit = pass_manager.run(qc)
print(f"\nGate originali: {qc.count_ops()}")
print(f"Gate dopo transpilation: {isa_circuit.count_ops()}")
# Il transpiler aggiunge swap gates perche l'hardware ha connettivita limitata
# Esegui con SamplerV2 Primitive
sampler = Sampler(backend)
job = sampler.run([isa_circuit], shots=4096)
print(f"\nJob ID: {job.job_id()}")
print("Attendere risultati dall'hardware quantistico...")
print("(tipicamente 1-5 minuti in coda + 30 secondi di esecuzione)")
result = job.result()
counts = result[0].data.c.get_counts()
print(f"\nRisultati hardware reale (4096 shots):")
for state, count in sorted(counts.items()):
print(f" |{state}⟩: {count} ({count/4096*100:.1f}%)")
# Output tipico su hardware reale (con noise):
# |00⟩: ~1850 (45.2%) <- meno di 50% a causa del noise
# |11⟩: ~1920 (46.9%)
# |01⟩: ~150 (3.7%) <- errori da gate noise
# |10⟩: ~176 (4.3%) <- errori da gate noise
Transpilace: Od logického obvodu k hardwaru
Logický obvod používá abstraktní hradla (H, CNOT atd.), ale každý procesor IBM má sadu různé nativní brány. Transpiler převádí logický obvod na nativní instrukce konkrétního hardwaru a také optimalizace směrování (fyzické qubity nejsou všechny vzájemně propojeny).
# Analisi della transpilation
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
service = QiskitRuntimeService(channel='ibm_quantum')
backend = service.least_busy(operational=True, simulator=False)
# Circuito di esempio: 3 qubit, multiple gate
qc = QuantumCircuit(3)
qc.h(0)
qc.cx(0, 1)
qc.cx(1, 2)
qc.rx(0.5, 0)
qc.ry(1.0, 1)
# Transpilation a diversi livelli di ottimizzazione
for opt_level in [0, 1, 2]:
pm = generate_preset_pass_manager(backend=backend, optimization_level=opt_level)
transpiled = pm.run(qc)
ops = transpiled.count_ops()
total_gates = sum(ops.values())
print(f"Optimization level {opt_level}: {total_gates} gates totali, ops={ops}")
# L'IBM Heron ha come native gates: CZ, RZ, SX, X
# Il transpiler decompone ogni gate logico in queste native gate
# Ottimizzazione level 2 riduce tipicamente il circuit depth del 20-40%
Důležitá omezení, která je třeba mít na paměti
- Hluk hardwaru: Výsledky na skutečném hardwaru vždy obsahují chyby. Pokud potřebujete deterministické výsledky, nepoužívejte kvantový hardware – použijte simulátor pro vývoj a hardware pro finální ověření
- Limity hloubky okruhu: Brány musí být dokončeny před dekoherencí. Na IBM Heron 2026 maximální praktická hloubka a ~100-200 vrstev před nadměrným hlukem
- Čas fronty: Doba fronty na skutečném hardwaru se může pohybovat od minut do hodin. Podle toho plánujte vývojové pracovní postupy
- Univerzálnost brány: H + CNOT (nebo Toffoli) jsou univerzální — libovolné klasicky vyčíslitelný výpočet a vyjádřitelný pomocí těchto hradel
Závěry
Kvantová hradla jsou reverzibilní lineární transformace na stavovém vektoru — matematicky elegantní a výpočetně výkonné. Stát Bell demonstruje ve 2 branách něco, co nemá klasický ekvivalent: zapletení. Pracovní postup Qiskit v2 — návrh obvodu, transpilace, Sampler Primitive — a dostatečně vyzrálý, aby podporoval skutečný vývoj.
Následující článek používá tyto stavební bloky k sestavení prvního kvantového algoritmu výhoda: Groverův algoritmus pro kvadratické vyhledávání O(sqrt N) v nestrukturovaných databázích.







