Tutorial 5: Variational Quantum Eigensolver (VQE)
The Variational Quantum Eigensolver (VQE) is a leading hybrid quantum-classical algorithm designed for the Noisy Intermediate-Scale Quantum (NISQ) era. It calculates the ground-state energy of quantum systems (such as molecules) by combining shallow parameterized quantum circuits with classical numerical optimizers.
In this tutorial, you will calculate the ground-state electronic energy of the molecular hydrogen molecule () using the Quantum Virtual Machine (QVM).
π― Learning Objectives
- Understand the Rayleigh-Ritz variational principle in quantum mechanics.
- Formulate molecular electronic Hamiltonians as sums of Pauli operators.
- Design a hardware-efficient parameterized quantum ansatz .
- Evaluate expectation values using QVM's
HamiltonianandSimulator. - Optimize variational parameters using classical optimizers to find the ground state energy.
π¬ Mathematical Theory
1. The Variational Principle
For any Hermitian Hamiltonian operator and any normalized quantum trial state , the expectation value of energy is bounded below by the true ground-state eigenvalue :
The variational approach searches for parameter values that minimize this expectation value:
2. Molecular Hydrogen () Hamiltonian
In the STO-3G minimal basis at the equilibrium bond distance (), the electronic Hamiltonian of can be mapped via the Jordan-Wigner or parity transformation to a 2-qubit Hamiltonian:
With numerical coefficients (including nuclear repulsion energy offset ):
- ()
- ()
- ()
- ()
The true ground state energy of this matrix is:
3. The Parameterized Ansatz
We use a hardware-efficient 4-parameter ansatz consisting of parameterized rotation gates and entangling gates:
π» Python Implementation
import numpy as np
from scipy.optimize import minimize
from qvm.ir import QuantumCircuit
from qvm.simulator import Simulator
from qvm.observable import Hamiltonian
# 1. Define the H2 Hamiltonian in Pauli basis
OFFSET = -1.052373245772859 # Nuclear repulsion and constant energy offset (Hartree)
H = Hamiltonian.from_dict({
"ZI": -0.39793742484318045,
"IZ": 0.39793742484318045,
"ZZ": -0.01128010425623538,
"XX": 0.18093119978423156,
})
# 2. Define the parameterized quantum ansatz
def create_ansatz(params):
a, b, c, d = params
qc = QuantumCircuit(2)
# Layer 1: parameterized single-qubit rotations
qc.add_operation("ry", [0], params=[a])
qc.add_operation("ry", [1], params=[b])
# Entangling block
qc.add_operation("cx", [0, 1])
qc.add_operation("ry", [1], params=[c])
qc.add_operation("cx", [0, 1])
qc.add_operation("ry", [0], params=[d])
return qc
# 3. Cost function: evaluates expectation value <H> on QVM
sim = Simulator()
def energy_cost(params):
circuit = create_ansatz(params)
exp_val = sim.expectation_value(circuit, H)
return float(OFFSET + exp_val)
# 4. Classical Optimization (Nelder-Mead)
rng = np.random.default_rng(42)
initial_guess = rng.uniform(-np.pi, np.pi, 4)
res = minimize(
energy_cost,
initial_guess,
method="Nelder-Mead",
options={"maxiter": 500, "fatol": 1e-7}
)
vqe_energy = res.fun
# 5. Exact diagonalization of Hamiltonian matrix for comparison
H_matrix = H.to_matrix(2) + OFFSET * np.eye(4)
exact_ground_energy = float(np.linalg.eigvalsh(H_matrix)[0])
print(f"VQE Computed Ground State : {vqe_energy:.6f} Ha")
print(f"Exact Diagonalized Energy : {exact_ground_energy:.6f} Ha")
print(f"Absolute Energy Error : {abs(vqe_energy - exact_ground_energy):.2e} Ha")
# Verify convergence within chemical accuracy (< 0.0016 Ha ~ 1 kcal/mol)
assert abs(vqe_energy - exact_ground_energy) < 1.6e-3, "Failed to achieve chemical accuracy!"
print("\nSuccess: Chemical accuracy achieved!")Verified Execution Output
VQE Computed Ground State : -1.137306 Ha
Exact Diagonalized Energy : -1.137306 Ha
Absolute Energy Error : 2.14e-07 Ha
Success: Chemical accuracy achieved!β‘ Evaluating Expectation Values via REST API (/run)
The /run endpoint natively accepts the expectation_pauli parameter:
curl -X POST "http://127.0.0.1:8000/run" \
-H "Content-Type: application/json" \
-d '{
"source_type": "json",
"nqubits": 2,
"circuit": [
{"name": "ry", "qubits": [0], "params": [0.0]},
{"name": "ry", "qubits": [1], "params": [3.1415926535]},
{"name": "cx", "qubits": [0, 1]},
{"name": "ry", "qubits": [1], "params": [-0.111]},
{"name": "cx", "qubits": [0, 1]},
{"name": "ry", "qubits": [0], "params": [0.0]}
],
"expectation_pauli": {
"ZI": -0.397937,
"IZ": 0.397937,
"ZZ": -0.011280,
"XX": 0.180931
}
}'The response includes:
{
"expectation_value": -0.084933,
"nqubits": 2
}Adding the constant scalar offset yields .
ποΈ Advanced: QVM's Native VQE and QAOA Modules
QVM contains built-in classes in src/qvm/vqe.py and src/qvm/qaoa.py with automatic gradient calculation via the parameter-shift rule (src/qvm/gradient.py):
from qvm.vqe import VQE
from qvm.observable import Hamiltonian
vqe = VQE(ansatz_func=create_ansatz, hamiltonian=H, optimizer="cobyla")
result = vqe.compute_minimum_eigenvalue(initial_point=initial_guess)
print(result.eigenvalue + OFFSET)Next: REST API Reference.