Przejdź do głównej treści

Praktyczne wprowadzenie do kryteriów DiVincenzo z Qiskit 2

Wprowadzenie

Fizyk David DiVincenzo nakreślił pięć kluczowych wymagań dla każdej fizycznej implementacji komputera kwantowego, plus dwa dodatkowe kryteria dla komunikacji kwantowej. W tym notebooku doświadczysz każdego z kryteriów DiVincenzo poprzez praktyczne demonstracje w Qiskit. Zamiast zagłębiać się w teorię, każda sekcja krótko wyjaśnia jedno kryterium, a następnie udostępnia ćwiczenia z kodem w Qiskit 2. Będziesz uruchamiać Circuit na symulatorach i rzeczywistych urządzeniach IBM Quantum, aby zbadać każdą zasadę w praktyce.

Pięć kryteriów DiVincenzo dla obliczeń kwantowych:

  1. Skalowalny układ fizyczny z dobrze scharakteryzowanymi Qubit.
  2. Możliwość inicjalizacji Qubit do prostego stanu wzorcowego (np. |00…0〉).
  3. Długie czasy dekoherencji (koherencja Qubit znacznie dłuższa niż czas operacji Gate).
  4. Uniwersalny zestaw Gate kwantowych (możliwość wykonywania dowolnych operacji unitarnych).
  5. Możliwość pomiaru poszczególnych Qubit (odczyt stanu każdego Qubit).

(DiVincenzo opisał również dwa kryteria dla komunikacji kwantowej: możliwość wzajemnej konwersji stacjonarnych i „latających" Qubit oraz niezawodnego przesyłania latających Qubit między lokalizacjami. Uwzględniamy je w zalecanym ćwiczeniu na końcu tego notebooku.)

Każda z poniższych sekcji odpowiada jednemu kryterium. Użyjemy Qiskit, aby zilustrować koncepcję kodem i interaktywnymi eksperymentami, które możesz wypróbować. Na przykład zobaczymy, jak skalowanie liczby Qubit i głębokości Circuit wpływa na wyniki (kryterium 1), jak resetować i przygotowywać stany Qubit (kryterium 2), jak mierzyć Qubit na symulatorach i rzeczywistych urządzeniach (kryterium 4), jak Qiskit składa uniwersalne Gate (kryterium 3) i jak skończona koherencja (T₁, T₂) wpływa na obliczenia (kryterium 5). Po zakończeniu będziesz mieć głębszą intuicję co do tego, co każde kryterium DiVincenzo oznacza w praktyce i jak Qiskit umożliwia eksperymentowanie z nimi.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy
# Install necessary packages
!pip install qiskit[visualization] qiskit-ibm-runtime qiskit-aer qiskit_ibm_runtime

1. Kryterium 1 – Skalowalne, dobrze scharakteryzowane Qubit

Kryterium 1: „Skalowalny układ fizyczny z dobrze scharakteryzowanymi Qubit." Oznacza to, że potrzebujemy platformy sprzętowej, w której możemy zwiększać liczbę Qubit i nadal nimi niezawodnie sterować. Właściwości każdego Qubit (poziomy energii, wskaźniki błędów, połączenia itp.) powinny być dobrze poznane. Zasadniczo chcemy budować większe Circuit bez degradacji systemu. W praktyce, gdy skalujemy liczbę Qubit lub głębokość Circuit, narastają błędy i dekoherencja, więc demonstrowanie skalowalności oznacza również zrozumienie, jak rosnący rozmiar wpływa na wydajność.

Cel demonstracji: Użyj Qiskit, aby pokazać wpływ skalowania Circuit (pod względem liczby Qubit lub głębokości Gate) na wierność wyników. Zasymulujemy scenariusz idealny i zaszumiony, aby zobaczyć, jak większy system lub głębszy Circuit ulega dekoherencji i błędom.

Najpierw zbudujmy mały splątany stan (stan GHZ) na 3 Qubit, a następnie większy na 5 Qubit jako prosty test skalowalności. Stan GHZ n Qubit to 12(0...0+1...1)\frac{1}{\sqrt{2}}(|0...0\rangle + |1...1\rangle). W idealnej symulacji pomiar n-Qubitowego GHZ daje tylko dwa wyniki (same 0 lub same 1) z równym prawdopodobieństwem. Porównamy wynik idealny z wynikiem zaszumionym w miarę zwiększania n lub głębokości Circuit.

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import SamplerV2 as Sampler

# 3-qubit GHZ circuit
qc3 = QuantumCircuit(3, 3)
qc3.h(0)
qc3.cx(0, 1)
qc3.cx(1, 2)
qc3.measure([0, 1, 2], [0, 1, 2])

# 5-qubit GHZ circuit (scaling up the number of qubits)
qc5 = QuantumCircuit(5, 5)
qc5.h(0)
qc5.cx(0, range(1, 5)) # entangle qubit 0 with all others
qc5.measure(range(5), range(5))

# Transpile for a simulator backend
sim_backend = AerSimulator()
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc3 = pm.run(qc3)
isa_qc5 = pm.run(qc5)

# Run ideal simulations (no noise)
sampler = Sampler(mode=sim_backend)

job3 = sampler.run([isa_qc3], shots=1024)
result3 = job3.result()
counts3 = result3[0].data.c.get_counts()

job5 = sampler.run([isa_qc5], shots=1024)
result5 = job5.result()
counts5 = result5[0].data.c.get_counts()

print("3-qubit GHZ counts (ideal):", counts3)
plot_histogram(counts3, legend=['3-qubit ideal'], figsize=(6,4))
3-qubit GHZ counts (ideal): {'000': 531, '111': 493}

Quantum circuit diagram

print("5-qubit GHZ counts (ideal):", counts5)
plot_histogram(counts5, legend=['5-qubit ideal'], figsize=(6,4))
5-qubit GHZ counts (ideal): {'11111': 535, '00000': 489}

Code output

Oczekiwany wynik (przypadek idealny): Idealny 3-Qubitowy GHZ daje w przybliżeniu 50% 000 i 50% 111 w zliczeniach. 5-Qubitowy GHZ daje ~50% 00000 i 50% 11111. Żadne inne ciągi bitów nie pojawiają się, ponieważ stan jest idealnie w pełni koherentny i splątany. Na histogramie dla każdego Circuit powinny być widoczne dwa wysokie słupki odpowiadające wynikom: same zera i same jedynki.

Teraz zobaczmy, co dzieje się w środowisku zaszumionym. Użyjemy możliwości modelu szumów Qiskit Aer, aby naśladować błędy rzeczywistego urządzenia. Na przykład możemy pobrać właściwości backendu IBM, aby stworzyć model szumów uwzględniający błędy Gate, skończone czasy Gate, relaksację Qubit (T₁), defazowanie (T₂) i błędy odczytu. Użyjemy tutaj fałszywego backendu reprezentującego urządzenie IBM Quantum Brisbane, aby wygenerować model szumów i ponownie uruchomić Circuit GHZ.

Ćwiczenie 1a: Symulacja z szumem

Uzupełnij poniższy kod, aby zasymulować Circuit GHZ na zaszumionym symulatorze opartym na backendzie FakeBrisbane. Pokaże to, jak wydajność spada w miarę skalowania systemu w realistycznym środowisku szumów.

from qiskit_ibm_runtime.fake_provider import FakeBrisbane

# We will reuse the ideal circuits qc3 and qc5 and their results from the previous cell.

# --- YOUR CODE HERE ---

# 1. Create a fake backend for IBM Quantum Brisbane
###brisbane_backend = ...

# 2. Create a noisy AerSimulator from the fake backend's properties
###noisy_sim = ...

# 3. Transpile the circuits for the noisy simulator (this adapts them to the device's specific gates and connectivity)
###pm = ...

###isa_qc3_noisy = ...

###isa_qc5_noisy = ...

# 4. Run the noisy simulations using the Sampler and get the counts
###sampler = ...

###job3 = ...

###result3_noisy = ...

###counts3_noisy = ...

###job5 = ...

###result5_noisy = ...

###counts5_noisy = ...

# --- END YOUR CODE ---

# This part is done for you to print and plot the results:
print("3-qubit GHZ counts (noisy):", counts3_noisy)
plot_histogram(counts3_noisy, legend=['3-qubit noisy'], figsize=(6,4))
print("5-qubit GHZ counts (noisy):", counts5_noisy)
plot_histogram(counts5_noisy, legend=['5-qubit noisy'], figsize=(6,4))

Ćwiczenie 1b: Uruchomienie na prawdziwym komputerze kwantowym IBM

Poniższy kod uruchamia Circuit GHZ na prawdziwym komputerze kwantowym IBM. Pokaże to, jak wydajność spada na rzeczywistym urządzeniu.

# your_api_key = "deleteThisAndPasteYourAPIKeyHere"
# your_crn = "deleteThisAndPasteYourCRNHere"

# QiskitRuntimeService.save_account(
# channel="ibm_quantum_platform",
# token=your_api_key,
# instance=your_crn,
# name="fallfest-2025",
# )

# Check that the account has been saved properly
# service = QiskitRuntimeService(name="fallfest-2025")
# print(service.saved_accounts())

# We will reuse the ideal circuits qc3 and qc5 and their results from the previous cell.

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService(name="fallfest-2025")
real_backend = service.least_busy(operational=True, simulator=False)
print("Running on " + real_backend.name)

pm = generate_preset_pass_manager(backend=real_backend, optimization_level=1)
isa_qc3r = pm.run(qc3)
isa_qc5r = pm.run(qc5)

sampler = Sampler(mode=real_backend)

job3r = sampler.run([isa_qc3r], shots=1024)
result3r = job3r.result()
counts3r = result3r[0].data.c.get_counts()

job5r = sampler.run([isa_qc5r], shots=1024)
result5r = job5r.result()
counts5r = result5r[0].data.c.get_counts()

print("3-qubit GHZ counts (real):", counts3r)
plot_histogram(counts3r, legend=['3-qubit real'], figsize=(6,4))
print("5-qubit GHZ counts (real):", counts5r)
plot_histogram(counts5r, legend=['5-qubit real'], figsize=(6,4))

Oczekiwany wynik (zaszumiony vs. idealny): Przy szumach, zarówno symulowanych, jak i na rzeczywistym urządzeniu, stan GHZ jest mniej doskonały. Zobaczysz dodatkowe wyniki poza samymi zerami i samymi jedynkami. Dla 3 Qubit zamiast 100% w 000/111, część prawdopodobieństwa wycieka do innych ciągów bitów (np. 001, 010 itp.) z powodu błędów Gate lub dekoherencji odwracającej niektóre Qubit. Dla 5 Qubit efekt jest jeszcze bardziej wyraźny; większy Circuit (więcej Qubit i bramek CNOT) gromadzi więcej błędów, więc szczyty dla samych zer i samych jedynek są niższe, a pojawia się wiele innych wyników. Tendencja ta ilustruje wyzwanie skalowalności: w miarę skalowania utrzymanie wysokiej wierności bez korekcji błędów staje się coraz trudniejsze.

Spostrzeżenie: Skalowalny komputer kwantowy musi zachowywać korelacje kwantowe w miarę rozrostu systemu. Nasze przykłady pokazują, jak zwiększanie liczby Qubit i głębokości Gate powoduje spadek wierności wyników w obecności szumu. Pozostałe kryteria dotyczą utrzymywania tych Qubit w dobrej kondycji (niski błąd, możliwość inicjalizacji itp.) w miarę skalowania.

2. Kryterium 2 – Inicjalizacja Qubitów

Kryterium 2: „Możliwość inicjalizacji stanu qubitów do prostego stanu odniesienia, np. |000…〉." Wszystkie qubity powinny niezawodnie rozpoczynać pracę w znanym stanie referencyjnym (zazwyczaj stanie podstawowym |0〉 dla każdego qubitu). Inicjalizacja jest niezbędna, aby algorytmy startowały od czystej karty. W praktyce, na urządzeniach kwantowych IBM każdy qubit jest automatycznie resetowany do |0〉 na początku każdego wykonania obwodu. Qiskit udostępnia również instrukcje umożliwiające resetowanie qubitów lub przygotowywanie niestandardowych stanów w trakcie obliczeń.

Cel demonstracji: Pokazać, jak inicjalizować qubity w Qiskit – zarówno na początku, jak i w środku obwodu. Zademonstrujemy użycie instrukcji reset oraz metod przygotowywania stanów.

Ćwiczenie 2: Przygotowanie określonego stanu

W poniższym bloku kodu uzupełnij QuantumCircuit, aby przygotować stan 10|10\rangle. Oznacza to, że qubit 0 powinien być w stanie 0|0\rangle, a qubit 1 w stanie 1|1\rangle. Użyj odpowiedniej bramki i instrukcji, aby to osiągnąć.

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator

# Create a circuit to initialize qubits to |10> and verify by measurement
qc_init = QuantumCircuit(2, 2)

# --- YOUR CODE HERE ---

# 1. Set qubit 1 to the |1> state

# 2. Explicitly reset qubit 0 to the |0> state

# --- END YOUR CODE ---

qc_init.measure([0, 1], [0, 1])
qc_init.draw('mpl')
# Run the circuit and check the outcome
sim_backend = AerSimulator()
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc_init = pm.run(qc_init)

sampler = Sampler(mode=sim_backend)

job = sampler.run([isa_qc_init], shots=1024)
result = job.result()
counts = result[0].data.c.get_counts()

print("Outcome of |10> state measured in Z-basis:", counts)
plot_histogram(counts)

Powinieneś zobaczyć 10 (binarnie: qubit1=1, qubit0=0) ze 100% prawdopodobieństwem w symulacji, co potwierdza, że qubit 1 został pomyślnie przygotowany w stanie |1〉, a qubit 0 w stanie |0〉.

Teraz, do bardziej ogólnego przygotowywania stanów, Qiskit umożliwia inicjalizację do dowolnych stanów za pomocą metody initialize. Na przykład przygotujmy qubit w stanie +=(0+1)/2|+\rangle = (|0\rangle+|1\rangle)/\sqrt{2}, który jest stanem superpozycji, oraz parę qubitów w stanie Bella (00+11)/2(|00\rangle+|11\rangle)/\sqrt{2}:

import numpy as np

# Initialize a single qubit in |+> state and measure in Z-basis
qc_plus = QuantumCircuit(1, 1)
state_plus = [1/np.sqrt(2), 1/np.sqrt(2)] # amplitude for |0> and |1>
qc_plus.initialize(state_plus, 0)
qc_plus.measure(0, 0)

# Initialize two qubits in a Bell state manually
qc_bell = QuantumCircuit(2, 2)
bell_state = [1/np.sqrt(2), 0, 0, 1/np.sqrt(2)] # amplitudes for |00>,|01>,|10>,|11>
qc_bell.initialize(bell_state, [0, 1])
qc_bell.measure([0, 1], [0, 1])

# Transpile and run the initialization circuits
isa_qc_plus = pm.run(qc_plus)
job_plus = sampler.run([isa_qc_plus], shots=1024)
result_plus = job_plus.result()
counts_plus = result_plus[0].data.c.get_counts()

print("Outcome of |+> state measured in Z-basis:", counts_plus)

isa_qc_bell = pm.run(qc_bell)
job_bell = sampler.run([isa_qc_bell], shots=1024)
result_bell = job_bell.result()
counts_bell = result_bell[0].data.c.get_counts()

print("Outcome of Bell state measured in Z-basis:", counts_bell)
Outcome of |+> state measured in Z-basis: {'1': 499, '0': 525}
Outcome of Bell state measured in Z-basis: {'00': 508, '11': 516}

Oczekiwane wyniki: Stan |+〉 pojedynczego qubitu po pomiarze da wynik 0 i 1 z prawdopodobieństwem około 50% dla każdego. Pomiar stanu Bella powinien dawać około 50% 00 i 50% 11. Jeśli to widzisz, potwierdza to, że inicjalizacja do tych stanów przebiegła pomyślnie.

Inicjalizacja w środku obwodu: Instrukcja reset z Qiskit może być używana w środku obwodu, aby ponownie zainicjalizować qubit do |0〉 w locie. Na przykład w kodach korekcji błędów lub algorytmach iteracyjnych często mierzy się qubit, a następnie resetuje go do ponownego użytku. Operacja reset jest deterministyczna – usuwa istniejący stan i sprowadza qubit z powrotem do stanu podstawowego.

Przykład na urządzeniu: Na sprzęcie takim jak ibmq_brisbane (127 qubitów) lub dowolnym urządzeniu IBM wszystkie qubity domyślnie startują w |0〉, gdy uruchamiane jest zadanie. Jeśli potrzebujesz innego stanu początkowego, na początku obwodu należy zastosować odpowiednie bramki (tak jak zrobiliśmy to z bramką X, aby uzyskać |1〉). Ciągła re-inicjalizacja (na potrzeby kwantowej korekcji błędów) jest aktywnym obszarem badań, ponieważ wykonanie jej szybko jest wyzwaniem. Na szczęście do podstawowego użytku możliwość rozpoczęcia od świeżego |0…0〉 jest dostępna, a my pokazaliśmy też, jak osiągnąć inne pożądane stany początkowe.

3. Kryterium 3 – Długi czas koherencji (dekoherencja a czas bramki)

Kryterium 3: „Długie odpowiednie czasy dekoherencji, znacznie dłuższe niż czas operacji bramki." Chodzi tu o potrzebę utrzymania przez qubity stanu kwantowego wystarczająco długo, aby wykonać niezbędne operacje. Każdy qubit charakteryzuje się czasem T₁ (czas relaksacji energii, jak szybko |1〉 rozpada się do |0〉) oraz czasem T₂ (czas defazowania, jak szybko traci się koherencję fazy względnej). Aby komputer kwantowy działał, te skale czasu powinny znacznie przewyższać czas trwania operacji bramki.

Cel demonstracji: Zbadać koherencję qubitu w Qiskit, pokazując wpływ dekoherencji na wyniki obwodu w zależności od długości wykonania. Użyjemy fałszywego Backend'u ze znanymi czasami T1/T2, aby zasymulować ten efekt.

Aby zademonstrować wpływ skończonej koherencji, zasymulujemy eksperyment zaniku T1. Przygotujemy qubit w stanie |1〉, odczekamy pewien czas za pomocą instrukcji delay, a następnie dokonamy pomiaru. Oczekujemy, że prawdopodobieństwo zmierzenia |1〉 będzie maleć wraz ze wzrostem opóźnienia.

# This part is done for you. We are creating a list of circuits,
# each with a different delay time.

time_delays_ns = [0, 50000, 100000, 150000, 200000, 250000, 300000] # delay durations in ns

decay_expts = []
for delay in time_delays_ns:
qc = QuantumCircuit(1, 1)
qc.x(0) # initialize qubit to |1>
if delay > 0:
qc.delay(delay, 0, unit='ns') # wait 'delay' nanoseconds
qc.measure(0, 0)
decay_expts.append(qc)

decay_expts[1].draw('mpl') # Visualize one of the circuits

Quantum circuit diagram

Ćwiczenie 3: Symulacja eksperymentu zaniku T1

Użyj teraz symulatora zaszumionego opartego na FakeVigo (który ma czasy T1 rzędu ~50–100 µs), aby uruchomić te obwody. Symulator automatycznie zastosuje błędy T1/T2 podczas instrukcji delay. Transpiluj obwody dla tego Backend'u i wykonaj je.

from qiskit_ibm_runtime.fake_provider import FakeVigoV2 as FakeVigo
from qiskit_aer import AerSimulator

# --- YOUR CODE HERE ---

# 1. Create a noisy simulator from the FakeVigo backend
###sim_vigo = ...

# 2. Transpile the list of circuits for this simulator
###pm = ...

###isa_decay_expts = ...

# 3. Use the Sampler to run all the transpiled circuits in a single job
###sampler = ...

###job = ...

###result = ...

# --- END YOUR CODE ---

# This part is done for you to analyze and print the results.
for idx, (delay, qc) in enumerate(zip(time_delays_ns, isa_decay_expts)):
counts = result[idx].data.c.get_counts()
p1 = counts.get('1', 0) / 1000 # Assuming 1000 shots
print(f"Delay {delay} ns: P(qubit=1) = {p1:.3f}")

Powinieneś zaobserwować, że prawdopodobieństwo P(qubit=1) maleje wraz ze wzrostem czasu opóźnienia, podążając za krzywą zaniku wykładniczego charakterystyczną dla relaksacji T1. Bezpośrednio demonstruje to, jak skończony czas koherencji prowadzi do błędów obliczeniowych, jeśli obwód działa zbyt długo.

Wpływ na algorytmy: Jeśli spróbujesz uruchomić dłuższy algorytm (z wieloma sekwencyjnymi bramkami), całkowity czas wykonania może zbliżyć się do T2 lub go przekroczyć, powodując utratę koherencji stanu przed zakończeniem obwodu. Dlatego poprawa czasów koherencji i przyspieszenie bramek to dwa z najważniejszych celów w badaniach nad sprzętem kwantowym.

4. Kryterium 4 – Uniwersalny zestaw bramek kwantowych

Kryterium 4: „»Uniwersalny« zestaw bramek kwantowych." Oznacza to, że nasz sprzęt musi pozwalać na wykonanie dowolnego obliczenia kwantowego poprzez składanie skończonego zestawu podstawowych bramek. W klasycznym przetwarzaniu NAND jest uniwersalny; w kwantowym istnieje wiele wyborów uniwersalnych zestawów bramek (np. {H, T, CNOT} lub natywne bramki danej maszyny). Urządzenia IBM mają na przykład zestaw natywnych operacji – dowolne obroty jednoQubitowe oraz bramki CNOT między określonymi Qubitami – które razem są uniwersalne. Zadaniem Qiskit jest często kompilacja bramek wysokiego poziomu do tych bramek bazowych.

Cel demonstracji: Zilustrowanie uniwersalności bramek przez pokazanie, jak Qiskit dekompozuje bramki. Weźmiemy bramkę nienatywną (np. trzuQubitową bramkę Toffoli, CCX) i zobaczymy, jak jest ona rozkładana na natywne bramki bazowe urządzenia. Dowodzi to, że dostarczony zestaw bramek jest rzeczywiście uniwersalny – potrafi odtworzyć bardziej złożone operacje.

Najpierw sprawdźmy, jakie są bramki bazowe typowego backendu IBM. Odpytamy konfigurację urządzenia (lub jego fałszywej wersji). Dla przykładu, bramki bazowe ibmq_brisbane: Powinieneś/powinnaś zaobserwować, że prawdopodobieństwo P(qubit=1) maleje wraz ze wzrostem czasu opóźnienia, podążając za krzywą wykładniczego zaniku charakterystyczną dla relaksacji T1. Bezpośrednio demonstruje to, w jaki sposób skończony czas koherencji prowadzi do błędów obliczeniowych, gdy Circuit działa zbyt długo.

Wpływ na algorytmy: Jeśli spróbujesz dłuższego algorytmu (z wieloma kolejnymi bramkami), całkowity czas wykonania może zbliżyć się do T2 lub go przekroczyć, powodując utratę koherencji stanu jeszcze przed zakończeniem obliczeń. Dlatego poprawa czasów koherencji i przyspieszanie bramek to dwa z najważniejszych celów w badaniach nad sprzętem kwantowym.

from qiskit_ibm_runtime.fake_provider import FakeBrisbane
fake_brisbane = FakeBrisbane()
print("Basis gates for ibmq_brisbane:", fake_brisbane.configuration().basis_gates)
Basis gates for ibmq_brisbane: ['ecr', 'id', 'rz', 'sx', 'x']

Wynik może wyglądać mniej więcej tak: ['id', 'rz', 'sx', 'x', 'ecr']. Są to prymitywne operacje natywnie obsługiwane przez sprzęt (Identity/brak operacji, obrót RZ, bramka sqrt(X), bramka X i controlled-X). Każda inna bramka musi zostać złożona z tych elementów. Wiadomo, że ten zestaw jest uniwersalny dla obliczeń kwantowych (zasadniczo obroty jednoQubitowe plus splątująca bramka dwuQubitowa tworzą zestaw uniwersalny).

Weźmy teraz bramkę Toffoli (CCX) jako przypadek testowy. CCX odwraca qubit docelowy tylko wtedy, gdy oba qubity kontrolne mają wartość 1. Nie jest to bramka natywna na sprzęcie IBM. Qiskit udostępnia instrukcję ccx, ale pod spodem zostanie ona rozłożona.

Ćwiczenie 4: Dekompozycja bramki Toffoli

Uzupełnij poniższy kod, aby zbudować Circuit z bramką Toffoli (CCX), a następnie użyj Qiskit do jej rozbicia na natywne bramki bazowe backendu FakeBrisbane.

from qiskit import QuantumCircuit
from qiskit_ibm_runtime.fake_provider import FakeBrisbane

# The fake_brisbane backend from the previous cell is reused here.

# --- YOUR CODE HERE ---

# 1. Create a circuit that can accommodate a Toffoli gate
###qc_toffoli = ...

# Apply a CCX gate with controls on qubits 0, 1 and target on qubit 2

# 2. Transpile the circuit to the fake Brisbane backend
###pm = ...

###isa_qc_toffoli = ...

# --- END YOUR CODE ---

print("Toffoli circuit before decomposition:")
print(qc_toffoli)

print("\nToffoli circuit after transpiling to Brisbane basis:")
# The .draw() method will now show the decomposed circuit
print(isa_qc_toffoli.draw(fold=120))

W transpilowanym wyniku powinieneś/powinnaś zobaczyć CCX zastąpioną sekwencją prostszych bramek, takich jak rz, sx i ecr. Dowodzi to, że natywne bramki są wystarczające do wyrażenia bramki Toffoli.

Uniwersalność w praktyce: Powyższe ćwiczenie pokazuje, że złożona bramka trójQubitowa została zbudowana z prostszych elementów. Ogólnie rzecz biorąc, dowolna unitarna operacja wieloQubitowa może być złożona z bramek 1- i 2-qubitowych. Transpiler jest kluczowym elementem każdego stosu oprogramowania kwantowego, ponieważ stanowi pomost między abstrakcyjnymi algorytmami, które chcemy wykonać, a fizycznymi operacjami, jakie dane urządzenie kwantowe faktycznie może przeprowadzić.

Przykład urządzenia: Urządzenie ibmq_brisbane korzysta z architektury Eagle z bramkami bazowymi pokazanymi powyżej. Oznacza to, że każdy algorytm wysłany na te maszyny zostanie przekonwertowany na sekwencje tych operacji. To kryterium dotyczy w zasadzie sterowalności – mamy wystarczająco dużo możliwości sterowania, aby wykonać na naszych Qubitach dowolną potrzebną operację.

5. Kryterium 5 – Pomiar Qubita

Kryterium 5: „Zdolność do pomiaru specyficznego dla Qubita." Stan każdego Qubita musi być mierzalny (zazwyczaj w bazie obliczeniowej, |0〉 lub |1〉). Innymi słowy, po uruchomieniu Circuit kwantowego musimy odczytać każdy Qubit jako klasyczny bit 0/1. To kryterium dotyczy posiadania niezawodnych detektorów dla każdego Qubita oraz możliwości wyboru, które Qubity mierzyć.

Cel demonstracji: Pokazanie, jak wykonywać pomiary w Qiskit na symulatorach i rzeczywistych urządzeniach, oraz podkreślenie różnic (takich jak szum pomiarowy). Zmierzymy kilka Qubitów w różnych stanach i przeanalizujemy wyniki. Pokażemy również, jak mogą pojawiać się błędy odczytu, porównując wyniki z symulatora i sprzętu.

Najpierw prosty przykład pomiaru:

qc_measure = QuantumCircuit(2, 2)
qc_measure.x(0) # qubit 0 -> |1>, qubit 1 stays |0>
qc_measure.measure([0, 1], [0, 1])
qc_measure.draw('mpl')

Quantum circuit diagram

sim_backend = AerSimulator()
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc_measure = pm.run(qc_measure)
job = sampler.run([isa_qc_measure], shots=1000)
result = job.result()
counts = result[0].data.c.get_counts()

print("Simulator measurement counts:", counts)
Simulator measurement counts: {'01': 1000}

Spodziewamy się 1000 zliczeń 01 na symulatorze. Teraz zobaczmy błąd pomiarowy w działaniu, symulując go. Możemy dodać błąd odczytu do naszego symulatora Aer. Qiskit Aer pozwala nam zdefiniować ReadoutError i dołączyć go do Qubitów w modelu szumu.

Ćwiczenie 5: Symulacja błędu odczytu

Uzupełnij kod, aby zdefiniować prosty model błędu odczytu, w którym każdy Qubit ma 2% szansę na błędny odczyt (0 odczytane jako 1 lub 1 odczytane jako 0). Następnie uruchom Circuit pomiaru z tym modelem szumu.

from qiskit_aer.noise import NoiseModel, ReadoutError

# --- YOUR CODE HERE ---

# 1. Define a 2% readout error for each single qubit.
# The format is a list of lists of probabilities: [[P(0|0), P(1|0)], [P(0|1), P(1|1)]]
# P(A|B) is the probability of measuring A given the state was |B>.
###ro_error = ...

# 2. Create a new noise model
###noise_model_ro = ...

# 3. Add the readout error to all qubits in the noise model
... # Hint: Use the add_all_qubit_readout_error method

# --- END YOUR CODE ---

sim_backend.set_options(noise_model=noise_model_ro)
pm = generate_preset_pass_manager(backend=sim_backend, optimization_level=1)
isa_qc_measure = pm.run(qc_measure)

# Run the measurement circuit with readout noise
sampler = Sampler(mode=sim_backend)

job = sampler.run([isa_qc_measure], shots=1024)
result = job.result()
counts = result[0].data.c.get_counts()

print("Simulation with 2% readout error:", counts)

Symulowane wyniki pokażą pewne błędne zliczenia (np. 11, 00, 10), podobne do tych, które może generować rzeczywisty sprzęt, demonstrując wpływ niedoskonałego pomiaru.

Przykład urządzenia: Na rzeczywistym urządzeniu, takim jak ibmq_brisbane, można uruchomić ten sam Circuit i prawdopodobnie zobaczyć podobne, niezerowe zliczenia dla błędnych wyników. Dane kalibracyjne urządzenia podają błąd odczytu dla każdego Qubita. Możliwość celowania w określone Qubity i ich odczytu jest kluczowa, a zrozumienie charakterystyki ich błędów jest niezbędne do uzyskania sensownych wyników. Uruchamianie na rzeczywistym urządzeniu zostało zademonstrowane w Ćwiczeniu 1b: Uruchamianie na prawdziwym komputerze kwantowym IBM.

Kryteria komunikacji kwantowej (latające Qubity)

DiVincenzo wymienił również dwa kryteria specyficzne dla komunikacji kwantowej, istotne przy budowie sieciowego komputera kwantowego:

  1. Zdolność do wzajemnej konwersji stacjonarnych i latających Qubitów. (Np. mapowanie Qubita w procesorze na foton, który może przemieszczać się.)
  2. Zdolność do wiernego przesyłania latających Qubitów między lokalizacjami. (Np. wysyłanie fotonowego Qubita przez włókno bez utraty informacji kwantowej.)

Wykracza to poza standardowe zastosowania Qiskit, ponieważ Qiskit zajmuje się głównie stacjonarnymi Qubitami na chipie. Możemy jednak zilustrować koncepcję tych kryteriów prostym przykładem: teleportacją kwantową. Teleportacja pokazuje konwersję stanu stacjonarnego Qubita na informację przenoszoną przez splątaną parę (część „latająca") i komunikację klasyczną, która jest następnie używana do odtworzenia stanu na innym stacjonarnym Qubicie w innym miejscu.

Moduł Teleportacja kwantowa w ramach Qiskit w salach lekcyjnych, przygotowany przez dr Katie McCormick, poprowadzi cię przez jeden z najbardziej fascynujących protokołów w informacji kwantowej: teleportację kwantową, w której stan kwantowy (Qubit) jest przesyłany od Alicji do Boba przy użyciu splątania i zaledwie dwóch klasycznych bitów. Poznasz pełną procedurę teleportacji krok po kroku – jak przygotować splątaną parę Bella, wykonać pomiar w bazie Bella po stronie Alicji, przesłać wyniki klasyczne i zastosować właściwą bramkę kwantową na Qubicie Boba, aby doskonale odtworzyć oryginalny stan. Po drodze zbadasz, dlaczego teleportowanie informacji Qubita nie narusza twierdzenia o zakazie klonowania ani nie przekracza prędkości światła. Poprzez praktyczne ćwiczenia na sprzęcie IBM Quantum lub symulatorach zyskasz praktyczne rozumienie pomiaru, splątania i sterowania wyprzedzającego w działaniu.

Opanowując teleportację kwantową, zrozumiesz, jak kodować, przesyłać i odtwarzać informacje kwantowe między oddzielnymi węzłami – tworząc podstawy dla sieci kwantowych, systemów retransmiterów, bezpiecznych schematów komunikacji i skalowalnych modularnych obliczeń kwantowych.

Związek z kryteriami 6 i 7: W prawdziwej sieci kwantowej wspólna splątana para byłaby tworzona przez dystrybucję „latających" Qubitów (np. fotonów) między lokalizacjami Alicji i Boba (Kryterium 7: wierne przesyłanie). Sam protokół teleportacji służy następnie jako sposób na odwzorowanie stanu stacjonarnego Qubita Alicji na jej połowę splątanej pary, efektywnie „wysyłając" go do Boba (Kryterium 6: interkonwersja). Qiskit pozwala nam doskonale symulować logikę protokołu, dostarczając konceptualny model tego, jak kryteria te są spełniane w architekturach komunikacyjnych.

Podsumowanie i wnioski

Zaprojektowaliśmy serię ćwiczeń skupionych na kodzie, aby zilustrować kryteria DiVincenzo przy użyciu Qiskit. Poprzez te praktyczne przykłady zbadałeś/zbadałaś, jak prawdziwa platforma obliczeniowa spełnia każde wymaganie:

  • Skalowalność: budowanie Circuitów na większej liczbie Qubitów i rozumienie skalowania szumu.
  • Inicjalizacja: używanie resetów i preparacji stanów, aby niezawodnie rozpoczynać obliczenia w znanych stanach.
  • Uniwersalne bramki: transpilowanie złożonych operacji do bramek bazowych maszyny, co dowodzi, że możemy wykonać dowolne obliczenia.
  • Pomiar: odczytywanie Qubitów i radzenie sobie z realistycznymi błędami odczytu.
  • Koherencja: obserwowanie wpływu skończonego T₁, T₂ na wierność algorytmu i konieczność szybkiego wykonywania operacji w stosunku do dekoherencji.

Dla kompletności dotknęliśmy również aspektów komunikacji kwantowej poprzez moduł Teleportacja kwantowa w ramach Qiskit w salach lekcyjnych, łącząc ostatnie dwa kryteria (latające Qubity).

Na koniec warto zauważyć, jak te kryteria łączą się w prawdziwym komputerze kwantowym, takim jak IBM. Urządzenie takie jak ibmq_brisbane ma 127 nadprzewodnikowych Qubitów (Kryterium 1), z których każdy startuje w stanie |0〉 (Kryterium 2), z skalibrowanym zestawem bramek i kompilatorami zapewniającymi uniwersalność (Kryterium 4), mikrofalowymi rezonatorami odczytu dla każdego Qubita (Kryterium 5) oraz czasami koherencji rzędu setek mikrosekund w porównaniu do nanosekund operacji (Kryterium 3). W przypadku eksperymentów z sieciami kwantowymi IBM i inne firmy badają konwersję mikrofalowo-optyczną dla latających Qubitów oraz splątywanie odległych Qubitów (Kryteria 6 i 7); to są aktywne obszary badań.

Wykonując ćwiczenia w tym notatniku, nie tylko poznałeś/poznałaś definicje kryteriów DiVincenzo, ale dotknąłeś/dotknęłaś ich poprzez kod – budując intuicję co do tego, co każde wymaganie oznacza dla rzeczywistego sprzętu kwantowego i algorytmów. Śmiało rozszerzaj te eksperymenty i miłych obliczeń kwantowych!