Instanțe și extensii
Acest capitol va acoperi mai mulți algoritmi cuantici variațional, printre care:
- Variational Quantum Eigensolver (VQE)
- Subspace Search VQE (SSVQE)
- Variational Quantum Deflation (VQD)
- Quantum Sampling Regression (QSR)
Folosind acești algoritmi, vom învăța mai multe idei de design care pot fi integrate în algoritmi variationali personalizați, cum ar fi ponderi, penalizări, supra-eșantionare și sub-eșantionare. Te încurajăm să experimentezi cu aceste concepte și să îți împărtășești descoperirile cu comunitatea.
Cadrul Qiskit patterns se aplică tuturor acestor algoritmi — dar vom evidenția explicit pașii doar în primul exemplu.
Variational Quantum Eigensolver (VQE)
VQE este unul dintre cei mai utilizați algoritmi cuantici variationali, oferind un șablon pe care ceilalți algoritmi îl pot extinde.
Pasul 1: Maparea intrărilor clasice la o problemă cuantică
Prezentare teoretică
Structura VQE este simplă:
- Pregătește operatorii de referință
- Pornim din starea și ajungem la starea de referință
- Aplică forma variațională pentru a crea un ansatz
- Trecem din starea în
- Bootstrap la dacă avem o problemă similară (găsită de obicei prin simulare clasică sau eșantionare)
- Fiecare optimizer va fi bootstrapped diferit, rezultând un set inițial de vectori de parametri (de exemplu, dintr-un punct inițial ).
- Evaluează funcția de cost pentru toate stările pregătite pe un calculator cuantic.
- Folosește un optimizer clasic pentru a selecta următorul set de parametri .
- Repetă procesul până la convergență.
Acesta este un simplu ciclu de optimizare clasică în care evaluăm funcția de cost. Unii optimizatori pot necesita evaluări multiple pentru a calcula un gradient, a determina următoarea iterație sau a evalua convergența.
Iată exemplul pentru următorul operator observabil:
Implementare
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime scipy
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit.library import TwoLocal
import numpy as np
theta_list = (2 * np.pi * np.random.rand(1, 8)).tolist()
observable = SparsePauliOp.from_list([("II", 2), ("XX", -2), ("YY", 3), ("ZZ", -3)])
reference_circuit = QuantumCircuit(2)
reference_circuit.x(0)
variational_form = TwoLocal(
2,
rotation_blocks=["rz", "ry"],
entanglement_blocks="cx",
entanglement="linear",
reps=1,
)
ansatz = reference_circuit.compose(variational_form)
ansatz.decompose().draw("mpl")
def cost_func_vqe(parameters, ansatz, hamiltonian, estimator):
"""Return estimate of energy from estimator
Parameters:
params (ndarray): Array of ansatz parameters
ansatz (QuantumCircuit): Parameterized ansatz circuit
hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
estimator (Estimator): Estimator primitive instance
Returns:
float: Energy estimate
"""
estimator_job = estimator.run([(ansatz, hamiltonian, [parameters])])
estimator_result = estimator_job.result()[0]
cost = estimator_result.data.evs[0]
return cost
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()
Putem folosi această funcție de cost pentru a calcula parametrii optimi
# SciPy minimizer routine
from scipy.optimize import minimize
x0 = np.ones(8)
result = minimize(
cost_func_vqe, x0, args=(ansatz, observable, estimator), method="COBYLA"
)
result
message: Optimization terminated successfully.
success: True
status: 1
fun: -5.999999982445723
x: [ 1.741e+00 9.606e-01 1.571e+00 2.115e-05 1.899e+00
1.243e+00 6.063e-01 6.063e-01]
nfev: 136
maxcv: 0.0
Pasul 2: Optimizarea problemei pentru execuție cuantică
Vom selecta Backend-ul cel mai puțin ocupat și vom importa componentele necesare din qiskit_ibm_runtime.
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime import Session, EstimatorOptions
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
print(backend)
<IBMBackend('ibm_brisbane')>
Vom transpila Circuit-ul folosind managerul de pași preset cu nivelul de optimizare 3 și vom aplica layout-ul corespunzător operatorului observabil.
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
isa_ansatz = pm.run(ansatz)
isa_observable = observable.apply_layout(layout=isa_ansatz.layout)
Pasul 3: Executare folosind primitivele Qiskit Runtime
Suntem acum pregătiți să rulăm calculul pe hardware IBM Quantum®. Deoarece minimizarea funcției de cost este puternic iterativă, vom porni o sesiune Runtime. Astfel, va trebui să așteptăm în coadă o singură dată. Odată ce job-ul începe să ruleze, fiecare iterație cu actualizări ale parametrilor va rula imediat.
x0 = np.ones(8)
estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)
with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)
result = minimize(
cost_func_vqe,
x0,
args=(isa_ansatz, isa_observable, estimator),
method="COBYLA",
options={"maxiter": 200, "disp": True},
)
session.close()
print(result)
Pasul 4: Post-procesare, returnarea rezultatului în format clasic
Putem observa că rutina de minimizare s-a terminat cu succes, ceea ce înseamnă că am atins toleranța implicită a optimizatorului clasic COBYLA. Dacă avem nevoie de un rezultat mai precis, putem specifica o toleranță mai mică. Aceasta poate fi într-adevăr situația, deoarece rezultatul a diferit cu câteva procente față de cel obținut de simulator mai sus.
Valoarea lui x obținută este cea mai bună estimare curentă a parametrilor care minimizează funcția de cost. Dacă iterăm pentru a obține o precizie mai mare, acele valori ar trebui folosite în locul lui x0 utilizat inițial (un vector de unu).
În final, remarcăm că funcția a fost evaluată de 96 de ori în procesul de optimizare. Aceasta poate diferi de numărul de pași de optimizare, deoarece unii optimizatori necesită evaluări multiple ale funcției într-un singur pas, cum ar fi atunci când estimează un gradient.
Subspace Search VQE (SSVQE)
SSVQE este o variantă a VQE care permite obținerea primelor valori proprii ale unui operator observabil cu valorile proprii , unde . Fără pierdere de generalitate, presupunem că . SSVQE introduce o idee nouă prin adăugarea de ponderi pentru a prioritiza optimizarea termenului cu ponderea cea mai mare.
Pentru a implementa acest algoritm, avem nevoie de stări de referință mutual ortogonale , adică pentru . Aceste stări pot fi construite folosind operatori Pauli. Funcția de cost a acestui algoritm este: