Loading...
Loading...
VQE & QAOA
Variational Quantum Eigensolver (VQE) and Quantum Approximate Optimization Algorithm (QAOA) are hybrid quantum-classical algorithms designed for near-term quantum devices. They use short quantum circuits evaluated on quantum hardware, with classical optimizers tuning the parameters.
The variational principle from quantum mechanics states that the expectation value of a Hamiltonian in any trial state is always greater than or equal to the true ground-state energy. VQE exploits this by preparing parameterized quantum states (ansätze) and minimizing their energy using a classical optimizer.
This hybrid approach is powerful because the quantum computer handles the classically intractable part — computing expectation values of exponentially large operators — while the classical computer performs the parameter optimization it does best.
Variational Principle
Expectation Value
Parameter Optimization
QAOA was inspired by quantum annealing and applies the variational approach to combinatorial optimization problems. It alternates between a problem Hamiltonian (which encodes the objective function) and a mixer Hamiltonian (which explores the solution space).
While QAOA's performance on large-scale problems is still being studied, it has shown promising results on Max-Cut and other graph problems, and serves as a testbed for understanding quantum advantage in optimization.
Variational algorithms are promising but face significant challenges on current hardware. Noise limits circuit depth, barren plateaus make training difficult for large circuits, and measurement overhead grows with the number of Hamiltonian terms.
Research at Identity Lab focuses on designing hardware-aware ansätze for neutral atom platforms and developing error mitigation strategies to improve result quality on noisy devices.
Runnable implementations you can copy and experiment with.
A complete QAOA implementation for a 4-node ring graph, finding the optimal cut.
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np
# QAOA parameters
n_qubits = 4
p = 1
beta, gamma = 0.5, 0.8
edges = [(0, 1), (1, 2), (2, 3), (3, 0)]
qc = QuantumCircuit(n_qubits, n_qubits)
# Initial superposition
qc.h(range(n_qubits))
# Problem Hamiltonian (Cost layer)
for u, v in edges:
qc.cx(u, v)
qc.rz(gamma, v)
qc.cx(u, v)
# Mixer Hamiltonian
for q in range(n_qubits):
qc.rx(2 * beta, q)
# Measure
qc.measure(range(n_qubits), range(n_qubits))
# Execute
simulator = AerSimulator()
job = simulator.run(qc, shots=2048)
counts = job.result().get_counts()
best_cut = max(counts, key=counts.get)
print(f"Best cut string: {best_cut}")A minimal VQE example estimating the ground state energy of a 2-qubit Hamiltonian using a hardware-efficient ansatz.
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np
def ansatz(theta):
qc = QuantumCircuit(2)
qc.ry(theta[0], 0)
qc.ry(theta[1], 1)
qc.cx(0, 1)
qc.ry(theta[2], 0)
qc.ry(theta[3], 1)
return qc
def expectation(theta):
qc = ansatz(theta)
qc.measure_all()
simulator = AerSimulator()
job = simulator.run(qc, shots=4096)
counts = job.result().get_counts()
# Expectation of ZZ (toy Hamiltonian: H = ZZ)
energy = 0
for bitstring, count in counts.items():
sign = 1 if bitstring.count('1') % 2 == 0 else -1
energy += sign * count
return energy / 4096
# Simple grid search (replace with SPSA for real problems)
best_energy = float('inf')
best_params = None
for t0 in np.linspace(0, np.pi, 10):
for t1 in np.linspace(0, np.pi, 10):
for t2 in np.linspace(0, np.pi, 10):
for t3 in np.linspace(0, np.pi, 10):
e = expectation([t0, t1, t2, t3])
if e < best_energy:
best_energy = e
best_params = [t0, t1, t2, t3]
print(f"Best energy: {best_energy:.4f}")
print(f"Best params: {best_params}")A minimal PennyLane VQE example estimating the ground state energy of a 2-qubit Hamiltonian using a hardware-efficient ansatz.
import pennylane as qml
import numpy as np
n_qubits = 2
dev = qml.device('default.qubit', wires=n_qubits)
@qml.qnode(dev)
def circuit(params):
qml.RY(params[0], wires=0)
qml.RY(params[1], wires=1)
qml.CNOT(wires=[0, 1])
qml.RY(params[2], wires=0)
qml.RY(params[3], wires=1)
return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))
# Simple grid search
best_energy = float('inf')
best_params = None
for p0 in np.linspace(0, np.pi, 10):
for p1 in np.linspace(0, np.pi, 10):
for p2 in np.linspace(0, np.pi, 10):
for p3 in np.linspace(0, np.pi, 10):
e = circuit([p0, p1, p2, p3])
if e < best_energy:
best_energy = e
best_params = [p0, p1, p2, p3]
print(f"Best energy: {best_energy:.4f}")
print(f"Best params: {best_params}")