Sari la conținutul principal

Primul tău experiment cuantic

Introducere

În videoclipul următor, Olivia Lanes te ghidează prin conținutul acestei lecții. Alternativ, poți deschide videoclipul de pe YouTube pentru această lecție într-o fereastră separată.

Până acum, ai rulat primul tău circuit cuantic și ai învățat bazele calculului cuantic: cum sunt reprezentate stările cuantice, cum acționează porțile asupra acelor stări și cum sunt implicate caracteristici cuantice precum superpoziția și entanglement-ul. Acum este momentul să pui toate acestea în practică și să rezolvi prima ta problemă pe un calculator cuantic.

Vom explora peisajul mai larg al problemelor potrivite pentru calculul cuantic într-o lecție ulterioară. Deocamdată, ne vom concentra pe o problemă din domeniul simulării naturii: folosirea unui calculator cuantic ca înlocuitor mai curat și mai controlabil al unui sistem cuantic natural. De fapt, aceasta a fost prima aplicație pe care Richard Feynman a imaginat-o pentru calculatoarele cuantice în anii 1980. Cum a spus el celebru: „Natura nu este clasică, drace, și dacă vrei să faci o simulare a naturii, mai bine o faci mecanică cuantică..."

În această lecție, vom urma acel principiu pentru a simula interacțiunea dintre doi spini, pe care îi poți imagina ca niște magneți minusculi. În funcție de semnul interacțiunii lor, ei ar putea prefera să se alinieze și să indice în aceeași direcție, sau să se anti-alinieze și să indice în direcții opuse. Ne vom concentra pe cel de-al doilea caz, deoarece duce adesea la un comportament mai interesant — și mai provocator. Odată ce înțelegem acest mic sistem cu doi qubiți, vom arăta cum aceleași idei se extind, permițând calculatoarelor cuantice să profite de scalarea lor exponențială la simularea sistemelor mari de spini.

Doi magneți care interacționează

Pentru această problemă, vom folosi doi qubiți, câte unul pentru fiecare spin din modelul nostru. Fiecare spin poate indica în sus (starea qubit-ului 0|0\rangle), în jos (starea qubit-ului 1|1\rangle) sau în superpoziție a celor două stări.

Dacă spinii au o interacțiune antiferromagnetică, înseamnă că vor să se anti-alinieze, deci când unul este în sus, celălalt vrea să fie în jos, și invers.

Acum să presupunem că există și un câmp magnetic care indică de la stânga la dreapta în sistemul nostru. Deoarece acest câmp indică perpendicular față de direcția obișnuită sus-jos a spinilor, se numește câmp transversal. Acest câmp poate răsturna spinii, ceea ce face ca configurația cu cea mai mică energie să fie o superpoziție specifică de aranjamente de spini sus-jos, mai degrabă decât un singur tipar definit de spini.

Putem descrie toate aceste efecte folosind un obiect matematic numit Hamiltonian. Hamiltonianul ne spune energia sistemului pentru un aranjament dat de spini:

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

unde JJ este un coeficient care controlează intensitatea interacțiunii dintre spini, iar hxh_x este un coeficient pentru intensitatea câmpului magnetic extern. Z1Z0Z_1 Z_0 recompensează sau penalizează spinii în funcție de dacă sunt aliniați sau anti-aliniați, iar X0X_0 și X1X_1 reprezintă efectul de răsturnare a spinilor al câmpului magnetic.

În fizică, sistemele tind să se stabilizeze în starea cu energia cea mai mică posibilă, numită starea fundamentală. Găsirea acestei stări cu energie minimă este o problemă frecventă, dar necesită tehnici de optimizare care depășesc scopul acestei lecții.

În schimb, vom pune o întrebare mai simplă: Dacă pregătim spinii într-o stare anume, care este energia acelei stări?

Pentru a răspunde la aceasta, vom:

  1. Pregăti spinii într-o stare la alegerea noastră
  2. Măsura energia acelei stări folosind Hamiltonianul de mai sus

Aceasta este exact tipul de calcul care apare în algoritmii cuantici mai mari, cum ar fi algoritmii variaționali, pe care îi poți explora în cursuri ulterioare.

Implementarea în Qiskit

Înainte să scriem cod, avem nevoie de puțin context. Când rulăm un circuit cuantic, terminăm întotdeauna prin măsurarea qubiților. Dar există două tipuri diferite de întrebări pe care le-am putea dori să le punem despre rezultatul acelei măsurători: Uneori, vrem doar să știm care este starea qubit-ului. Alteori, vrem să știm, dată starea cuantică, care este valoarea unei cantități fizice, cum ar fi energia?

În Qiskit, aceste două tipuri de întrebări sunt gestionate de două instrumente diferite, numite primitive.

Sampler răspunde la primul tip de întrebare. Rulează circuitul de mai multe ori și ne spune cât de des măsurăm fiecare rezultat posibil, cum ar fi 00, 01, 10 sau 11. Rezultatul este o histogramă care arată probabilitatea fiecărui rezultat al măsurătorii.

Estimator răspunde la al doilea tip de întrebare. În loc să ne dea o histogramă, combină mai multe măsurători în culise pentru a calcula un singur număr, cum ar fi energia stării conform unui Hamiltonian pe care îl furnizăm.

Pentru a te ajuta să înțelegi când și de ce am folosi fiecare dintre aceste instrumente, vom parcurge două fluxuri de lucru complete (numite „tipare Qiskit") aplicate aceluiași sistem cu doi qubiți.

Fluxul de lucru al tiparelor Qiskit

Fluxul de lucru al tiparelor Qiskit este un cadru general pe care îl folosim pentru a rezolva probleme cuantice cu Qiskit. Împarte o sarcină de calcul cuantic în patru pași:

  1. Maparea problemei la un model care poate fi reprezentat prin circuite cuantice
  2. Optimizarea circuitului pentru a fi rulat pe un backend specific
  3. Executarea circuitului optimizat pe backend-ul selectat
  4. Post-procesarea datelor brute de măsurare

Experimentul 1: Folosește Sampler pentru a măsura starea

Mapare

În general, pasul de mapare este locul unde ne dăm seama cum să reprezentăm o problemă din lumea reală în termeni de qubiți, operatori și măsurători. În multe aplicații, acesta este cel mai dificil și mai elaborat pas din flux — chiar și întrebări simple, cum ar fi „ce reprezintă fiecare qubit?" nu au întotdeauna răspunsuri clare.

În acest experiment, însă, maparea este deliberat simplă. Fiecare grad de libertate fizic se mapează direct pe un singur qubit. Datorită acestei corespondențe unu-la-unu, pasul de mapare se reduce la alegerea stării cuantice pe care vrem să o pregătim și la scrierea unui circuit care pregătește și măsoară acea stare.

Aici, vom pregăti o stare Bell entanglată, similară cu cea din prima lecție a acestui curs:

Ψ=12(1001)\vert\Psi\rangle = \frac{1}{\sqrt{2}}(\vert 10\rangle - \vert 01\rangle)
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# Import Qiskit primitives
from qiskit import QuantumCircuit

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)

# Measure state
qc.measure_all()

# Draw circuit
qc.draw("mpl")

Output of the previous code cell

Optimizare

Înainte să rulăm circuitul nostru pe un calculator cuantic (sau pe un simulator dacă ți-ai epuizat timpul gratuit pe calculatoare cuantice reale pentru luna respectivă), trebuie să îl pregătim pentru execuție. Acest pas se numește optimizare. (Notă: această utilizare a cuvântului „optimizare" poate fi confuză. În calculul cuantic, problemele de optimizare se referă la o clasă specifică de probleme. Aici, folosim optimizarea pentru a descrie un pas de pregătire necesar prin care trece fiecare circuit cuantic înainte de a putea fi rulat eficient pe hardware.)

În timpul optimizării:

  1. Alegem backend-ul — fie un calculator cuantic real, fie un simulator.
  2. Atribuim qubiții circuitului nostru qubiților fizici de pe dispozitiv.
  3. Rescriem circuitul folosind doar porțile pe care calculatorul cuantic le poate efectua efectiv.
  4. Implementăm opțional tehnici de atenuare și suprimare a erorilor pentru a reduce efectele zgomotului.

În Qiskit, acest lucru este gestionat automat de transpiler. Odată ce alegi backend-ul, transpiler-ul face toată munca pentru a pregăti circuitul tău pentru execuție, fără să trebuiască să ajustezi manual porțile sau atribuirile qubiților. Transpiler-ul oferă de asemenea diferite niveluri de optimizare, care pot ajuta la reducerea erorilor dacă este necesar. Optimizarea se face în etape numite „treceri". Deci această optimizare va fi gestionată de pass_manager în codul de mai jos. Pentru a afla mai multe despre erori și atenuarea erorilor, consultă cursul Quantum Computing in Practice al Oliviei Lanes.

# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService

## Load the Qiskit Runtime service
# QiskitRuntimeService.save_account(
# channel="ibm_quantum_platform",
# token="YOUR_TOKEN_HERE",
# overwrite=True,
# set_as_default=True,
# )
# service = QiskitRuntimeService(channel="ibm_quantum_platform")

# Or load saved credentials
service = QiskitRuntimeService()

# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_fez
# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

qc_isa.draw("mpl")

Output of the previous code cell

Executare

Acum suntem gata să executăm! Vom încărca Sampler, apoi vom trimite jobul la backend.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

Sau, dacă folosești un simulator, poți decomenta și rula această celulă în schimb:

## Load the backend sampler
# from qiskit.primitives import BackendSamplerV2

## Load the Aer simulator and generate a noise model based on the currently-selected backend.
# from qiskit_aer import AerSimulator
# from qiskit_aer.noise import NoiseModel

# noise_model = NoiseModel.from_backend(backend)

## Define a simulator using Aer, and use it in Sampler.
# backend_sim = AerSimulator(noise_model=noise_model)
# sampler_sim = BackendSamplerV2(backend=backend_sim)

## Alternatively, load a fake backend with generic properties and define a simulator.
## backend_gen = GenericBackendV2(num_qubits=18)
## sampler_gen = BackendSamplerV2(backend=backend_gen)
job = sampler.run([qc_isa], shots=100)
# job = sampler_sim.run([qc_isa]) # uncomment if you want to run on a simulator
res = job.result()
counts = res[0].data.meas.get_counts()

Post-procesare

from qiskit.visualization import plot_histogram

print("counts = ", counts)
plot_histogram(counts)
counts =  {'10': 49, '01': 50, '11': 1}

Output of the previous code cell

Vedem că majoritatea numărătorilor sunt fie în 01, fie în 10, ceea ce înseamnă că atunci când un qubit a fost măsurat ca 0, celălalt era 1, și invers. Aceasta este consistent cu starea Bell Ψ\vert \Psi^- \rangle pe care am pregătit-o.

Experimentul 2: Folosește Estimator pentru a măsura energia

Acum că am văzut cum se eșantionează o stare cuantică, să folosim Estimator pentru a calcula energia stării noastre Bell Ψ=12(0110)\vert \Psi^- \rangle = \frac{1}{\sqrt{2}}(\vert 01 \rangle - \vert 10 \rangle).

Mapare

Ca memento, energia sistemului este determinată de interacțiunea dintre spini (JJ) și câmpul magnetic extern (hxh_x), capturată de Hamiltonian:

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

Fiecare termen din Hamiltonian ne spune cum contribuie o anumită combinație de spini la energie. În Qiskit, putem reprezenta acești termeni ca operatori Pauli, care sunt doar etichete pentru acțiuni simple asupra qubiților:

  • Z1Z0Z_1 Z_0 acționează cu ZZ pe ambii qubiți.
  • X0X_0 acționează cu XX pe qubit-ul 0.
  • X1X_1 acționează cu XX pe qubit-ul 1.

Un SparsePauliOp în Qiskit este o modalitate de a stoca o listă a acestor operatori Pauli împreună cu coeficienții lor numerici. Acești operatori Pauli sunt observabilele pe care vrem ca calculatorul cuantic să le măsoare — cantitățile care ne spun despre sistem. Folosind Estimator, putem calcula valoarea medie a fiecărei observabile pe starea noastră și le putem combina conform coeficienților din Hamiltonian pentru a obține energia totală.

# Import Qiskit primitives
from qiskit.quantum_info import SparsePauliOp

# Parameters
J = 1.0 # antiferromagnetic coupling (J<0)
hx = -0.5 # transverse field strength

# 1. Define the Hamiltonian H = J Z1 Z2 + hx (X1 + X2)
obs = SparsePauliOp.from_list([("ZZ", J), ("XI", hx), ("IX", hx)])

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)
<qiskit.circuit.instructionset.InstructionSet at 0x1387ed630>

Observă că am omis linia qc.measure_all() din codul nostru. Aceasta se datorează faptului că cu Estimator, nu trebuie să specificăm unde să măsurăm în circuit. Vom spune pur și simplu ce observabile vrem estimate, iar Qiskit se ocupă de măsurători în culise.

Optimizare

Pasul de optimizare continuă ca înainte, cu adăugarea de a ne asigura că observabilele noastre sunt scrise și ele într-un mod pe care calculatorul cuantic îl poate înțelege.

# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)

qc_isa.draw("mpl")

Output of the previous code cell

Executare

În pasul de Executare, vom încărca Estimator, apoi vom trimite circuitul împreună cu lista de observabile pe care vrem să le estimeze la calculatorul cuantic.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import EstimatorV2 as Estimator

estimator = Estimator(mode=backend)
# Load the backend sampler

# noise_model = NoiseModel.from_backend(backend)

# Use Aer simulator in Estimator
# estimator_sim = BackendEstimatorV2(backend=backend_sim)

# Alternatively, load a fake backend with generic properties and define a simulator.
# backend_gen = GenericBackendV2(num_qubits=18)
# estimator_gen = BackendEstimatorV2(backend=backend_gen)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()

# Uncomment lines below to run the job on the Aer simulator with noise model from real backend
# job = estimator_sim.run([[qc_isa,obs_isa]])
# res=job.result()

Post-procesare

În final, în pasul de post-procesare, afișăm pur și simplu energia calculată în culise de Estimator.

print(res[0].data.evs)
-0.9934112021453058

Aceasta este energia stării noastre!

Concluzie

În această lecție, am învățat cum să pregătim o stare cuantică simplă cu doi qubiți reprezentând doi spini care interacționează. Am văzut cum să folosim Sampler pentru a observa distribuția rezultatelor măsurătorilor și cum să folosim Estimator pentru a calcula energia stării conform Hamiltonianului. Pe parcurs, am văzut cum Hamiltonianul codifică interacțiunile dintre spini și efectele unui câmp extern, și cum stări diferite pot avea energii diferite.

Extensie la mulți spini

Până acum, ne-am uitat doar la doi spini, ceea ce este suficient de simplu pentru a fi analizat manual. În sistemele fizice reale, cum ar fi un magnet sau un alt material complex, există adesea mulți spini care interacționează. Când numărul de spini crește, Hamiltonianul devine mai complex și găsirea stării cu energie minimă devine mult mai dificilă. Aici calculatoarele cuantice pot ajuta: pregătind diferite stări și estimând energiile lor, putem explora configurații cu energie mică mai eficient decât calculatoarele clasice pentru sisteme mari.

O extensie naturală a acestui experiment ar fi să creștem numărul de qubiți pentru a reprezenta mai mulți spini și să ajustăm modul în care spinii sunt pregătiți pentru a încerca să găsim starea cu energie minimă. Această abordare este esența metodelor variaționali, despre care poți afla în cursul Variational Quantum Algorithms.

Există și alte abordări cuantice pentru studierea energiilor stărilor fundamentale care depășesc tehnicile variaționali. Aceste metode nu sunt acoperite aici, dar sunt introduse în cursul Quantum Diagonalization Algorithms dacă ești interesat să afli mai multe.

Obiectiv de învățare

Întoarce-te la începutul Experimentului 2 și încearcă din nou cu o stare de superpoziție diferită. Poți găsi o stare cu energie chiar mai mică decât cea pe care am folosit-o?

This translation based on the English version of 7 mai 2026