Estimarea energiei stării fundamentale a lanțului Heisenberg cu VQE
Estimare de utilizare: 37 de minute pe un procesor Heron (NOTĂ: Aceasta este doar o estimare. Timpul tău de execuție poate varia.)
Rezultate ale învățării
După finalizarea acestui tutorial, te poți aștepta să înțelegi următoarele informații:
- Cum să modelezi un lanț de spinuri Heisenberg ca Hamiltonian cuantic folosind Qiskit
- Cum să folosești optimizatorul SPSA pentru a estima energia stării fundamentale a unui sistem cuantic
- Cum să execuți fluxuri de lucru variaționali pe hardware cuantic IBM® folosind primitivele și sesiunile Qiskit Runtime
Cerințe prealabile
Se recomandă să te familiarizezi cu aceste subiecte:
Context
Lanțul de spinuri Heisenberg este unul dintre cele mai studiate modele din fizica materiei condensate și magnetismul cuantic. Descrie o rețea unidimensională de spinuri cuantice interacționante, unde spinurile vecine sunt cuplate prin interacțiuni de schimb. Hamiltonianul pentru modelul Heisenberg izotrop cu un câmp magnetic extern este dat de:
unde , și sunt operatorii Pauli care acționează pe site-ul , suma rulează peste perechile de vecini apropiați, sunt constantele de cuplare de schimb (izotrope în acest tutorial), iar reprezintă un câmp magnetic extern dependent de site. În acest tutorial, valorile câmpului magnetic sunt eșantionate aleator din intervalul . Rețineți că în implementarea de mai jos, setul de perechi „vecini apropiați" este determinat de cuplarea nativă a hardware-ului backend între primii qubiți, care ar putea să nu formeze un lanț liniar strict în funcție de topologia dispozitivului.
Înțelegerea energiei stării fundamentale a acestui Hamiltonian este de o importanță fundamentală în fizică. Starea fundamentală codifică informații despre tranzițiile de fază cuantice, structura entanglementului și ordonarea magnetică. Clasic, calculul exact al energiei stării fundamentale devine intractabil pe măsură ce numărul de spinuri crește, deoarece dimensiunea spațiului Hilbert scalează exponențial ca pentru spinuri. Aceasta îl face un candidat natural pentru simularea cuantică.
Eigensolver-ul Cuantic Variațional (VQE) este un algoritm hibrid cuantic-clasic conceput pentru a estima energia stării fundamentale a unui Hamiltonian. Funcționează prin pregătirea unei stări cuantice parametrizate (numită ansatz) pe un calculator cuantic și măsurarea valorii de așteptare . Un optimizator clasic ajustează apoi iterativ parametrii pentru a minimiza această energie, valorificând principiul variațional care garantează că energia măsurată este întotdeauna o limită superioară pentru energia adevărată a stării fundamentale.
În acest tutorial, folosim ansatz-ul efficient_su2 din biblioteca de circuite Qiskit, care construiește straturi de rotații pe un singur qubit și porți de entanglement. Optimizarea este realizată folosind algoritmul Simultaneous Perturbation Stochastic Approximation (SPSA), care este bine adaptat pentru hardware cuantic zgomotos deoarece estimează gradienții folosind doar două evaluări de funcție pe iterație, indiferent de numărul de parametri.
Cerințe
Înainte de a începe acest tutorial, asigură-te că ai instalate următoarele:
- Qiskit SDK v2.0 sau o versiune mai recentă, cu suport pentru vizualizare
- Qiskit Runtime v0.44 sau o versiune mai recentă (
pip install qiskit-ibm-runtime)
Configurare
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-runtime
import numpy as np
import matplotlib.pyplot as plt
from typing import Sequence
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives import BaseEstimatorV2
from qiskit.circuit.library import XGate
from qiskit.circuit.library import efficient_su2
from qiskit.transpiler import PassManager
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler.passes.scheduling import (
ALAPScheduleAnalysis,
PadDynamicalDecoupling,
)
from qiskit_ibm_runtime import QiskitRuntimeService, Session, EstimatorV2
def visualize_results(results):
plt.plot(results["cost_history"], lw=2)
plt.xlabel("Number of function evaluations")
plt.ylabel("Energy")
plt.show()
Exemplu la scară mică
În această secțiune, parcurgem fiecare pas al tiparului Qiskit la scară mică, explicând componentele cheie pe măsură ce construim fluxul de lucru.
Pasul 1: Maparea intrărilor clasice la o problemă cuantică
- Intrare: Numărul de spinuri
- Ieșire: Ansatz și Hamiltonian care modelează lanțul Heisenberg
Construiește un ansatz și un Hamiltonian care modelează un lanț Heisenberg cu 10 spinuri. În acest pas, vom construi un Hamiltonian Heisenberg cu 10 spinuri peste harta de cuplare a backend-ului cel mai puțin aglomerat și vom pregăti ansatz-ul efficient_su2.
num_spins = 10
ansatz = efficient_su2(num_qubits=num_spins, reps=2)
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, min_num_qubits=num_spins, simulator=False
)
coupling = backend.target.build_coupling_map()
reduced_coupling = coupling.reduce(list(range(num_spins)))
edge_list = reduced_coupling.graph.edge_list()
ham_list = []
for edge in edge_list:
ham_list.append(("ZZ", edge, 0.5))
ham_list.append(("YY", edge, 0.5))
ham_list.append(("XX", edge, 0.5))
for qubit in reduced_coupling.physical_qubits:
ham_list.append(("Z", [qubit], np.random.random() * 2 - 1))
hamiltonian = SparsePauliOp.from_sparse_list(ham_list, num_qubits=num_spins)
ansatz.draw("mpl", style="iqp")

Pasul 2: Optimizarea problemei pentru execuția pe hardware cuantic
- Intrare: Circuit abstract, observabilă
- Ieșire: Circuit și observabilă țintă, optimizate pentru QPU selectat
Folosește funcția generate_preset_pass_manager din Qiskit pentru a genera automat o rutină de optimizare pentru circuitul nostru în raport cu QPU selectat. Alegem optimization_level=3, care oferă cel mai înalt nivel de optimizare al managerilor de pase presetate. Includem, de asemenea, pase de planificare ALAPScheduleAnalysis și PadDynamicalDecoupling pentru a suprima erorile de decoerență.
target = backend.target
pm = generate_preset_pass_manager(optimization_level=3, target=target)
pm.scheduling = PassManager(
[
ALAPScheduleAnalysis(durations=target.durations()),
PadDynamicalDecoupling(
durations=target.durations(),
dd_sequence=[XGate(), XGate()],
pulse_alignment=target.pulse_alignment,
),
]
)
isa_ansatz = pm.run(ansatz)
isa_observable = hamiltonian.apply_layout(isa_ansatz.layout)
isa_ansatz.draw("mpl", scale=0.6, style="iqp", fold=-1, idle_wires=False)

Pasul 3: Execuția folosind primitivele Qiskit
- Intrare: Circuit și observabilă țintă
- Ieșire: Rezultatele optimizării
Minimizează energia estimată a stării fundamentale a sistemului prin optimizarea parametrilor circuitului. Folosește primitiva Estimator din Qiskit Runtime pentru a evalua funcția de cost în timpul optimizării.
Deoarece am optimizat circuitul pentru backend în Pasul 2, putem evita transpilarea pe serverul Runtime setând skip_transpilation=True și transmițând circuitul optimizat. Pentru această demonstrație, vom rula pe un QPU folosind primitivele qiskit-ibm-runtime. Pentru a rula cu primitivele bazate pe statevector din qiskit, înlocuiește blocul de cod care folosește primitivele Qiskit Runtime cu blocul comentat.
În acest tutorial folosim Simultaneous Perturbation Stochastic Approximation (SPSA), care este un optimizator bazat pe gradient. În continuare oferim o scurtă introducere în el și codul pentru a implementa SPSA folosind Qiskit v2.0.
Introducere în SPSA
Simultaneous Perturbation Stochastic Approximation (SPSA) [1] este un algoritm de optimizare care aproximează întregul vector gradient folosind doar două apeluri de funcție la fiecare iterație. Fie funcția de cost cu parametri de optimizat, și vectorul de parametri la pasul al iterației. Pentru a calcula gradientul, se creează un vector aleator de dimensiune , unde fiecare element , , este eșantionat uniform din . Apoi, fiecare element al vectorului aleator este înmulțit cu o valoare mică pentru a crea o perturbare aleatoare. Gradientul este estimat astfel:
Intuitiv, deoarece o perturbare aleatoare este aplicată în timpul estimării gradientului, se preconizează că mici deviații în valorile exacte ale provenite din zgomot pot fi tolerate și compensate. De fapt, SPSA este cunoscut în special pentru robustețea sa față de zgomot și necesită doar două apeluri hardware pentru fiecare iterație. Prin urmare, este unul dintre optimizatoarele preferate pentru implementarea algoritmilor variaționali.
În acest tutorial, hiperparametrii pentru iterația , și , sunt calculați ca
unde valorile constante sunt , , , și . Aceste valori sunt selectate din [2]. Ajustarea adecvată a hiperparametrilor este necesară pentru a extrage o performanță bună din SPSA.
def spsa(
fun, x0, args=(), A=30, alpha=0.9, a=0.3, c=0.1, gamma=0.4, maxiter=100
):
nparams = len(x0)
x = np.copy(x0)
for i in range(maxiter):
a_i = a / (A + i + 1) ** alpha
c_i = c / (i + 1) ** gamma
delta_i = np.random.choice([-1, 1], nparams)
# two hardware calls
eval_1 = fun(x + c_i * delta_i, *args)
eval_2 = fun(x - c_i * delta_i, *args)
# compute the gradient and update the parameters
grad = (eval_1 - eval_2) / (2 * c_i) * np.reciprocal(delta_i)
x = x - a_i * grad
return x
def cost_func(
params: Sequence,
ansatz: QuantumCircuit,
hamiltonian: SparsePauliOp,
estimator: BaseEstimatorV2,
cost_history_dict: dict,
) -> float:
"""Ground state energy evaluation."""
energy = (
estimator.run([(ansatz, hamiltonian, [params])]).result()[0].data.evs
)
cost_history_dict["iters"] += 1
cost_history_dict["prev_vector"] = list(params)
cost_history_dict["cost_history"].append(float(energy[0]))
print(
f"Fx Iters. done: {cost_history_dict['iters']} [Current cost: {round(energy[0], 5)}]",
end="\r",
)
return energy
def solve(x0, isa_ansatz, isa_observable, maxiter=150):
cost_history_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
"y_min": None,
}
# Evaluate the problem using a QPU via Qiskit IBM Runtime
with Session(backend=backend) as session:
estimator = EstimatorV2(mode=session)
estimator.skip_transpilation = True
estimator.options.environment.job_tags = ["TUT_HSVQE"]
x_opt = spsa(
cost_func,
x0=x0,
args=(isa_ansatz, isa_observable, estimator, cost_history_dict),
maxiter=maxiter,
)
y_min = cost_func(
x_opt, isa_ansatz, isa_observable, estimator, cost_history_dict
)
return y_min, cost_history_dict
np.random.seed(42)
num_params = ansatz.num_parameters
params = 2 * np.pi * np.random.random(num_params)
Aici setăm maxiter = 50. Rețineți că deoarece fiecare iterație necesită două apeluri la funcție pentru a calcula gradientul, numărul total de apeluri de funcție va fi . maxiter poate fi crescut la orice valoare mai mare pentru o estimare mai bună a energiei.
maxiter = 50
spsa_min, spsa_history = solve(
params, isa_ansatz, isa_observable, maxiter=maxiter
)
Fx Iters. done: 101 [Current cost: -3.03843]
Pasul 4: Post-procesarea și returnarea rezultatului în formatul clasic dorit
- Intrare: Estimările energiei stării fundamentale în timpul optimizării
- Ieșire: Energia estimată a stării fundamentale
print(f"Estimated ground state energy: {spsa_min}")
Estimated ground state energy: [-3.03842968]
results = {
"spsa": spsa_history,
}
visualize_results(spsa_history)
Exemplu hardware la scară largă
Un exemplu hardware la scară largă nu este inclus în acest tutorial. Pe măsură ce numărul de qubiți crește, VQE întâmpină provocări semnificative din cauza fenomenului barren plateau: gradientul funcției de cost dispare exponențial cu dimensiunea sistemului, făcând optimizarea practic imposibilă pentru circuite mari. Combinat cu zgomotul hardware, aceasta înseamnă că scalarea VQE la lanțuri de spinuri mai mari nu produce rezultate reproductibile fiabil. Pentru abordări care depășesc aceste limitări, consultă secțiunea Pași următori de mai jos.
Provocare
Acum că ai o implementare VQE funcțională pentru lanțul Heisenberg, încearcă următoarele:
- Experimentează cu adâncimea ansatz: Modifică parametrul
repsînefficient_su2(de exemplu, încearcăreps=1șireps=3). Cum afectează adâncimea ansatz energia estimată a stării fundamentale și viteza de convergență? La ce punct observi randamente descrescătoare sau instabilitate? - Ajustează hiperparametrii SPSA: Ajustează parametrii programului de rată de învățare (
a,c,alpha,gamma,A) și observă cum îi afectează convergența. Poți găsi o configurație care converge mai rapid decât valorile implicite folosite aici? - Compară topologiile de cuplare: În loc să folosești harta de cuplare nativă a backend-ului, încearcă să construiești un lanț liniar simplu cu vecini apropiați și compară rezultatele. Cum afectează conectivitatea hardware-ului fizic adâncimea circuitului transpilat și estimarea finală a energiei?
Referințe
[1] Spall, J. C. (2002). Implementation of the simultaneous perturbation algorithm for stochastic optimization. IEEE Transactions on Aerospace and Electronic Systems, 34(3), 817-823.
[2] Sahin, M. Emre, et al. (2025). Qiskit Machine Learning: an open-source library for quantum machine learning tasks at scale on quantum hardware and classical simulators. arXiv:2505.17756.
Pași următori
Dacă ți s-a părut interesant acest material, poate fi util și:
- Încearcă Diagonalizarea Cuantică Bazată pe Eșantionare (SQD): Așa cum s-a demonstrat în acest tutorial, VQE se confruntă cu provocări la scară din cauza barren plateau-urilor și a supraîncărcării ridicate de măsurători. IBM a dezvoltat Diagonalizarea Cuantică Bazată pe Eșantionare (SQD) ca o alternativă mai scalabilă. Spre deosebire de VQE, SQD evită complet optimizarea variaționalistă; în schimb, un calculator cuantic generează eșantioane, iar un calculator clasic proiectează Hamiltonianul pe un subspațiu generat de acele eșantioane și îl diagonalizează. Aceasta oferă o limită superioară pentru energia stării fundamentale cu semnificativ mai puține măsurători și fără susceptibilitate la barren plateau-uri. Urmează tutorialul SQD pentru a vedea această abordare în acțiune.
- Explorează cursul Algoritmi de Diagonalizare Cuantică: Aprofundează înțelegerea atât a VQE, cât și a SQD, inclusiv compromisurile lor, în cursul Algoritmi de diagonalizare cuantică de pe IBM Quantum Learning.