{ "cells": [ { "cell_type": "markdown", "id": "b8d4893b", "metadata": {}, "source": [ "# 15 - Variational Quantum Eigensolver (VQE)\n", "\n", "Find the ground-state energy of a simple Hamiltonian using a hybrid quantum-classical loop.\n", "\n", "**Concepts:** Ansatz, expectation values, parameter optimization" ] }, { "cell_type": "code", "execution_count": null, "id": "5749b5e7", "metadata": {}, "outputs": [], "source": [ "import quantsdk as qs\n", "import math\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "55d69a98", "metadata": {}, "source": [ "## Simple H2-like Hamiltonian\n", "\n", "We approximate the ground state of $H = -Z_0 Z_1 + 0.5 X_0 + 0.5 X_1$\n", "using a parameterized ansatz." ] }, { "cell_type": "code", "execution_count": null, "id": "fae11adc", "metadata": {}, "outputs": [], "source": [ "def ansatz(theta: float) -> qs.Circuit:\n", " \"\"\"Simple 2-qubit ansatz with one parameter.\"\"\"\n", " circuit = qs.Circuit(2, name=f\"ansatz-{theta:.3f}\")\n", " circuit.ry(0, theta)\n", " circuit.cx(0, 1)\n", " return circuit\n", "\n", "def measure_zz(theta: float, shots: int = 4000) -> float:\n", " \"\"\"Measure for the ansatz.\"\"\"\n", " circuit = ansatz(theta)\n", " circuit.measure_all()\n", " result = qs.run(circuit, shots=shots, seed=42)\n", " # Z eigenvalues: |0> -> +1, |1> -> -1\n", " exp = 0.0\n", " for bs, count in result.counts.items():\n", " z0 = 1 - 2 * int(bs[0])\n", " z1 = 1 - 2 * int(bs[1])\n", " exp += z0 * z1 * count\n", " return exp / shots\n", "\n", "def measure_x(theta: float, qubit: int, shots: int = 4000) -> float:\n", " \"\"\"Measure on a given qubit by rotating to X basis.\"\"\"\n", " circuit = ansatz(theta)\n", " circuit.h(qubit) # Rotate to X basis\n", " circuit.measure(qubit)\n", " result = qs.run(circuit, shots=shots, seed=42)\n", " exp = 0.0\n", " for bs, count in result.counts.items():\n", " val = 1 - 2 * int(bs[qubit])\n", " exp += val * count\n", " return exp / shots" ] }, { "cell_type": "code", "execution_count": null, "id": "e2baaaed", "metadata": {}, "outputs": [], "source": [ "def energy(theta: float) -> float:\n", " \"\"\"Compute = - + 0.5* + 0.5*.\"\"\"\n", " zz = measure_zz(theta)\n", " x0 = measure_x(theta, 0)\n", " x1 = measure_x(theta, 1)\n", " return -zz + 0.5 * x0 + 0.5 * x1\n", "\n", "# Parameter sweep\n", "thetas = np.linspace(0, 2 * math.pi, 20)\n", "energies = [energy(t) for t in thetas]\n", "\n", "best_idx = int(np.argmin(energies))\n", "print(f\"Best theta: {thetas[best_idx]:.3f} rad\")\n", "print(f\"Best energy: {energies[best_idx]:.3f}\")\n", "print(f\"\\nEnergy landscape (sample):\")\n", "for i in range(0, len(thetas), 4):\n", " bar = '#' * int((energies[i] + 2) * 10)\n", " print(f\" theta={thetas[i]:5.2f}: E={energies[i]:+.3f} {bar}\")" ] }, { "cell_type": "markdown", "id": "375e9da1", "metadata": {}, "source": [ "## Simple Gradient-Free Optimization" ] }, { "cell_type": "code", "execution_count": null, "id": "bb7f4fe7", "metadata": {}, "outputs": [], "source": [ "# Simple grid refinement optimizer\n", "best_theta = thetas[best_idx]\n", "for resolution in [0.5, 0.1, 0.01]:\n", " search = np.linspace(best_theta - resolution * 5, best_theta + resolution * 5, 11)\n", " search_energies = [energy(t) for t in search]\n", " best_theta = search[int(np.argmin(search_energies))]\n", "\n", "final_energy = energy(best_theta)\n", "print(f\"Optimized theta: {best_theta:.4f} rad\")\n", "print(f\"Final energy: {final_energy:.4f}\")" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }