Inicio/Blog/Cómo reducir en un 80% el número de disparos en algoritmos cuánticos variacionales
OptimizationVQEQAOAQPU

Cómo reducir en un 80% el número de disparos en algoritmos cuánticos variacionales

Técnicas prácticas para reducir el número de ejecuciones de circuito necesarias en VQE y QAOA: optimizadores frugales en disparos, trucos de estimación de gradientes y agrupación de mediciones.

FreeQuantumComputing
·· 8 min read

Cada vez que ejecutas un circuito cuántico en hardware real, cuesta tiempo de QPU y dinero. Los algoritmos variacionales como VQE y QAOA pueden requerir cientos de miles de ejecuciones de circuito para converger; a $0.075–$0.90 por tarea en QPU en la nube, eso se acumula rápidamente.

La buena noticia: la mayoría de las implementaciones por defecto son tremendamente ineficientes en disparos. Con las técnicas adecuadas, puedes reducir los requisitos de disparos en un 50–90% sin sacrificar la calidad de los resultados.

Por qué el número de disparos es tan alto por defecto

VQE calcula valores esperados de operadores de Pauli. Un hamiltoniano se descompone en una suma de términos de Pauli, y cada término requiere una ejecución de circuito separada. Para una molécula como H₂ (4 qubits), hay ~15 términos de Pauli. Para moléculas más grandes el número se dispara:

MoléculaQubitsTérminos de PauliDisparos ingenuos/iteración
H₂41515,000
LiH12631631,000
BeH₂14666666,000
H₂O141,0861,086,000

Con 200 iteraciones del optimizador, H₂O requiere de forma ingenua 217 millones de disparos. Las técnicas siguientes reducen esto en un 80–95%.

Técnica 1: Agrupación de mediciones (la mayor ganancia)

Muchos términos de Pauli conmutan: pueden medirse simultáneamente en una sola ejecución de circuito en lugar de por separado. Agrupar observables que conmutan es la mayor reducción disponible por sí sola.

from qiskit.primitives import StatevectorEstimator
from qiskit_nature.second_q.mappers import JordanWignerMapper
from qiskit_algorithms import VQE
from qiskit_algorithms.optimizers import COBYLA

# Qiskit automatically groups commuting Paulis in the Estimator primitive
# This reduces shots from O(n_terms) to O(n_groups) — often 5-10x reduction
estimator = StatevectorEstimator()

# With PennyLane, use grouping explicitly:
import pennylane as qml

H = qml.Hamiltonian(coeffs, observables)

# Group commuting terms — usually reduces term count by 5-10x
groups = qml.grouping.group_observables(observables, grouping_type='qwc')
print(f"Original terms: {len(observables)}, Groups: {len(groups)}")
# Original terms: 631, Groups: 68  (for LiH)

Ahorro esperado: 5–15× en hamiltonianos de química típicos.

Técnica 2: Optimizadores frugales en disparos

Los optimizadores clásicos como L-BFGS-B o ADAM asumen evaluaciones de función sin ruido: solicitan más evaluaciones de gradiente de las necesarias cuando los resultados son ruidosos. Los optimizadores frugales en disparos asignan disparos de forma adaptativa según la varianza de las mediciones.

from pennylane.optimize import AdaptiveOptimizer, ShotAdaptiveOptimizer

dev = qml.device("default.qubit", wires=4)

@qml.qnode(dev)
def circuit(params):
    # ansatz
    ...
    return qml.expval(H)

# ShotAdaptiveOptimizer: allocates more shots to high-variance directions
opt = ShotAdaptiveOptimizer(min_shots=10)

params = np.random.uniform(-np.pi, np.pi, n_params)
for i in range(100):
    params, _, shots_used = opt.step_and_cost(circuit, params)
    print(f"Step {i}: shots used = {shots_used}")

El optimizador comienza con pocos disparos por evaluación y los aumenta solo cuando el gradiente es incierto. Una ejecución típica de VQE usa 5–10× menos disparos frente a COBYLA con disparos fijos.

Técnica 3: Gradientes por desplazamiento de parámetros (usa menos evaluaciones)

La estimación ingenua de gradiente por diferencias finitas (f(x+ε) - f(x))/ε tiene alta varianza con ε pequeño y gran sesgo con ε grande. La regla de desplazamiento de parámetros da gradientes exactos con solo 2 evaluaciones de circuito por parámetro:

# PennyLane uses parameter-shift by default for gradients
@qml.qnode(dev, diff_method="parameter-shift")  # 2 evals per param
def circuit(params):
    ...

# Compare to finite-difference (requires 1 eval per param but biased):
@qml.qnode(dev, diff_method="finite-diff")  # 1 eval but approximate

# For large circuits, use "best" — PennyLane chooses adjoint on simulator,
# parameter-shift on hardware
@qml.qnode(dev, diff_method="best")
def circuit(params):
    ...

Con n parámetros, el desplazamiento de parámetros cuesta 2n evaluaciones por paso de gradiente. Usa optimizadores sin gradiente (COBYLA, SPSA, Nelder-Mead) cuando n sea grande.

Técnica 4: SPSA — Estimación estocástica de gradientes

La Aproximación Estocástica por Perturbación Simultánea (SPSA) estima el gradiente completo con solo 2 evaluaciones de circuito independientemente del número de parámetros, perturbando todos los parámetros simultáneamente:

from qiskit_algorithms.optimizers import SPSA

# SPSA: 2 evaluations per step regardless of parameter count
# vs parameter-shift: 2n evaluations per step
optimizer = SPSA(maxiter=300, learning_rate=0.1, perturbation=0.05)

# For 10 parameters:
# - Parameter shift: 2×10 = 20 evals/step × 300 steps = 6,000 total
# - SPSA: 2 evals/step × 300 steps = 600 total  ← 10x reduction

Mejor cuando: el circuito tiene muchos parámetros (> 10). El compromiso es una convergencia más lenta por paso, pero menos disparos totales.

Técnica 5: Terminación temprana + umbral de varianza

No ejecutes los circuitos hasta el final cuando el resultado ya es suficientemente bueno:

from pennylane.optimize import AdamOptimizer
import numpy as np

opt = AdamOptimizer(stepsize=0.02)
params = init_params.copy()
prev_energy = float('inf')

for step in range(max_steps):
    params, energy = opt.step_and_cost(circuit, params)

    # Stop when change is below shot-noise floor
    variance = 1.0 / np.sqrt(shots_per_eval)  # shot noise floor
    if abs(energy - prev_energy) < variance:
        print(f"Converged at step {step}")
        break

    prev_energy = energy

Muchas ejecuciones de VQE se estabilizan pronto; continuar solo desperdicia disparos en fluctuaciones de ruido.

Técnica 6: Arranque en caliente

Inicializa los parámetros de QAOA o VQE a partir de una solución clásica relacionada en lugar de valores aleatorios:

# For QAOA on Max-Cut: warm start from a greedy classical solution
import networkx as nx

G = nx.from_edgelist(edges)
classical_cut = nx.algorithms.approximation.one_exchange(G)

# Map classical solution to initial QAOA angles
# γ₀ ≈ π/4 for a good cut, β₀ ≈ π/8
init_gamma = [np.pi / 4]
init_beta = [np.pi / 8]

# Warm-started QAOA typically converges in 30-50% fewer iterations

Combinándolo todo: una plantilla práctica de VQE

import pennylane as qml
import numpy as np
from pennylane.optimize import ShotAdaptiveOptimizer

dev = qml.device("default.qubit", wires=n_qubits, shots=512)

# 1. Group commuting terms (5-10x reduction in circuit count)
grouped_H = qml.Hamiltonian(*qml.grouping.group_observables(H))

@qml.qnode(dev, diff_method="parameter-shift")
def ansatz(params):
    # Hardware-efficient ansatz
    for i in range(n_qubits):
        qml.RY(params[i], wires=i)
    for i in range(n_qubits - 1):
        qml.CNOT(wires=[i, i + 1])
    return qml.expval(grouped_H)

# 2. Use shot-adaptive optimizer
opt = ShotAdaptiveOptimizer(min_shots=50)

# 3. Warm start
params = warm_start_params(H)

# 4. Run with early stopping
for step in range(300):
    params, energy, shots = opt.step_and_cost(ansatz, params)
    if check_convergence(energy, shots):
        break

print(f"Ground state energy: {energy:.4f} Ha")

Referencia rápida: presupuesto de disparos por método

MétodoDisparos/pasoMejor para
COBYLA + disparos fijosn_terms × shotsPocos parámetros
Desplazamiento de parámetros + Adam2n_params × shotsCircuitos diferenciables
SPSA2 × shotsMuchos parámetros
ShotAdaptiveOptimizerAdaptativoVQE general
Paulis agrupados÷5–15×Aplicar siempre primero

Aplica primero la agrupación de mediciones: es la mayor ganancia individual y no requiere cambios en tu optimizador ni en tu circuito.

Relacionado: VQE con PennyLane · Guía de acceso a QPU · HLQuantum