Stochastic Adaptive Eigensolving with VASQE
VASQE — the Variational Adaptive Stochastic Quantum
Eigensolver — is ADAPT-VQE with a stochastic operator-selection rule.
ADAPT-VQE greedily appends the pool operator with the largest gradient magnitude;
VASQE instead samples the operator from a Boltzmann-like softmax of the
gradients at a selection temperature \(\tau\):
As \(\tau \to 0\) the probability concentrates on the largest-gradient operator, so VASQE reduces exactly to ADAPT-VQE.
As \(\tau \to \infty\) the distribution flattens toward uniform, letting the ansatz explore operators a greedy rule would never pick.
Convergence is unchanged from ADAPT-VQE — the loop still stops when \(\max_i |g_i| < \texttt{gradient\_tolerance}\). Only which operator is appended changes, so VASQE reuses all of the ADAPT machinery (pools, gradients, the growable ansatz, circuit profiling, ASE-calculator mode, frozen core, …).
Running VASQE
VASQE is an ASE calculator, exactly like ADAPT-VQE:
from ase import Atoms
from carcara.algorithms import VASQE
atoms = Atoms("H2", positions=[[4.0, 4.0, 3.63], [4.0, 4.0, 4.37]],
cell=[[8.0, 0, 0], [0, 8.0, 0], [0, 0, 8.0]], pbc=True)
atoms.calc = VASQE(basis="FAO", pool="fermionic", temperature=1.0,
h=0.20, max_iterations=12, gradient_tolerance=1e-5)
energy_ev = atoms.get_total_energy()
result = atoms.calc.vasqe_result # a VASQEResult (subclass of ADAPTVQEResult)
print(result.optimal_energy) # Hartree
print(result.operators) # the (stochastically) selected sequence
print(result.temperatures) # the tau used at each growth step
Selection is reproducible: the RNG is reseeded from seed at the start of every
run(), so a fixed seed gives a fixed operator sequence.
Temperature and annealing
The selection temperature can be held constant or annealed from a high
initial value (exploration) to a low final one (exploitation) over the growth
iterations. Four schedules are available via schedule:
|
\(\tau\) at step \(k\) of \(K\) |
Behaviour |
|---|---|---|
|
\(\tau_0\) |
fixed temperature ( |
|
\(\tau_0 + (\tau_f-\tau_0)\,k/(K-1)\) |
uniform cooling |
|
\(\tau_0\,(\tau_f/\tau_0)^{k/(K-1)}\) |
fast early cooling |
|
\(\tau_0 + (\tau_f-\tau_0)\,\log(1{+}k)/\log K\) |
slow early cooling |
# Anneal from a hot, exploratory tau=2.0 down to a greedy tau=0.01.
atoms.calc = VASQE(basis="FAO", temperature=2.0, final_temperature=0.01,
schedule="exponential", annealing_steps=12, h=0.20,
max_iterations=12, gradient_tolerance=1e-5)
atoms.get_total_energy()
annealing_steps sets the horizon \(K\) (default: max_iterations). A higher
initial temperature facilitates broader exploration of the ansatz space before the
schedule cools toward the greedy ADAPT-VQE choice.
The softmax and schedule helpers are also exposed directly:
import numpy as np
from carcara.algorithms import softmax_selection_probabilities, annealed_temperature
softmax_selection_probabilities(np.array([0.1, 0.9, 0.4]), tau=0.05) # ~[0,1,0]
annealed_temperature("exponential", 2.0, 0.01, step=3, horizon=12)
Excited states
Because selection is the single _select_operator()
hook, VASQE inherits both excited-state strategies from the driver framework, each
growing its ansatz stochastically:
# Deflation: ground + excited states, one after another.
levels = atoms.calc.energy_levels(num_states=2)
print(levels.in_units("eV"))
# Subspace search: ground + excited states simultaneously.
from carcara.algorithms import SubspaceVASQE
sv = SubspaceVASQE(basis="FAO", pool="fermionic", num_states=2,
temperature=0.5, h=0.20, gradient_tolerance=1e-5)
atoms.calc = sv
atoms.get_total_energy()
print(sv.subspace_result.in_units("eV"))
SubspaceVASQE combines the subspace-search machinery
(one shared ansatz over several orthogonal references, weighted-gradient screening)
with VASQE’s stochastic selection.
A complete, runnable script comparing the temperature schedules on H\ :sub:2 is
examples/10_VASQE_H2.py.