DeepPractise
DeepPractise

Simple VQE Demo

Track: Quantum Programming · Difficulty: Beginner–Intermediate · Est: 15 min

Simple VQE Demo

Overview

This page teaches a complete, tiny hybrid workflow:

  • choose a very small “Hamiltonian” (an observable we want to minimize)
  • build a parameterized circuit (ansatz)
  • estimate an expectation value from measurement results
  • update parameters using a simple classical loop

It matters because this is the core pattern behind many near-term workflows: classical code proposes circuits, quantum execution provides statistics, classical code updates the next step.

This is a learning demo, not chemistry-grade VQE.

Conceptual Mapping

From the Variational & NISQ module:

  • VQE minimizes an energy-like objective by tuning circuit parameters
  • the objective is an expectation value of an observable
  • evaluation is statistical (shots), not exact

From Foundations + Gates:

  • measurement is probabilistic (Born rule)
  • expectation values come from many samples
  • a single-qubit rotation is a simple example of a parameterized circuit

In code, the mapping is:

  • Ansatz → a QuantumCircuit with a parameter (like a rotation angle)
  • Hamiltonian (toy) → a measurement rule that assigns a number to outcomes
  • Expectation value → average of those numbers over many shots
  • Optimizer (toy) → try a few parameter values and pick the best

Code Walkthrough

We’ll use a 1‑qubit toy Hamiltonian that is “measure Z” (conceptually: prefer one computational basis state over the other).

Idea:

  • prepare a 1‑qubit state with a rotation parameter theta
  • measure many shots
  • map outcomes to values (+1 for 0, −1 for 1)
  • average to estimate the expectation value
import math
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
 
def estimate_z_expectation(theta, shots=500):
    qc = QuantumCircuit(1, 1)
    qc.ry(theta, 0)
    qc.measure(0, 0)
 
    sim = AerSimulator()
    counts = sim.run(qc, shots=shots).result().get_counts()
 
    # Map bit outcomes to Z eigenvalues: 0 -> +1, 1 -> -1
    p0 = counts.get('0', 0) / shots
    p1 = counts.get('1', 0) / shots
    return (+1) * p0 + (-1) * p1
 
# Toy “optimizer”: try a few angles and keep the best
candidates = [0, math.pi/4, math.pi/2, 3*math.pi/4, math.pi]
 
best_theta = None
best_value = None
 
for theta in candidates:
    value = estimate_z_expectation(theta)
    print(theta, value)
 
    if best_value is None or value < best_value:
        best_value = value
        best_theta = theta
 
print("best", best_theta, best_value)

Line by line (conceptual):

  • estimate_z_expectation builds a circuit with a parameter theta.
  • ry(theta, 0) is the ansatz: a tunable state preparation.
  • shots repeats the experiment to estimate probabilities.
  • counts is a histogram of outcomes.
  • We convert counts into an expectation value by mapping outcomes to numbers and averaging.
  • The “optimizer” is a simple loop that tries a few candidate angles.

Results & Interpretation

What you’re looking for is not a specific number. It’s the workflow behavior:

  • different parameters produce different measurement distributions
  • those distributions imply different expectation values
  • the classical loop can improve the objective by choosing better parameters

How to judge correctness (for a learning demo):

  • sanity check 1: results fluctuate a bit if you rerun (shot noise)
  • sanity check 2: increasing shots makes estimates more stable
  • sanity check 3: the “best” parameter should be reasonably consistent across reruns

Connection back to amplitudes:

  • ry(theta) changes amplitudes of |0⟩ and |1⟩
  • probabilities come from those amplitudes
  • expectation is a weighted average of outcome values

This is the key VQE lesson: you rarely compute an exact value; you estimate it from repeated measurements.

Turtle Tip

Turtle Tip

If your VQE demo feels “noisy,” that’s not a bug—it’s the point. The discipline is learning which randomness is expected (shots) and which indicates a real issue (wrong circuit, wrong mapping, wrong measurement).

Common Pitfalls

Common Pitfalls
  • Forgetting the outcome-to-value mapping (e.g., treating counts as the objective directly).
  • Using too few shots and thinking the optimizer is “unstable.”
  • Changing multiple things at once (ansatz + measurement + candidates) and not knowing what caused an effect.
  • Treating this toy as a realistic chemistry workflow; real VQE uses multiple Pauli terms and more careful optimizers.

Quick Check

Quick Check
  1. In this demo, what is the “ansatz” and what is the tunable parameter?
  2. Why do we need many shots to estimate an expectation value?
  3. What does the classical loop do conceptually?

What’s Next

Now you’ve seen an end-to-end hybrid loop. Next we’ll focus on debugging: how to use simulators, intermediate inspection, and sanity checks to understand “wrong” results productively.