diff --git a/docs/tutorials/spin-chain-vqe.ipynb b/docs/tutorials/spin-chain-vqe.ipynb index a23e8cd746e..6270f9df967 100644 --- a/docs/tutorials/spin-chain-vqe.ipynb +++ b/docs/tutorials/spin-chain-vqe.ipynb @@ -21,12 +21,34 @@ }, { "cell_type": "markdown", - "id": "49d868bf", + "id": "e28ad544", "metadata": {}, "source": [ + "## Learning outcomes\n", + "After completing this tutorial, you can expect to understand the following information:\n", + "- How to model a Heisenberg spin chain as a quantum Hamiltonian using Qiskit\n", + "- How to use the SPSA optimizer to estimate the ground-state energy of a quantum system\n", + "- How to execute variational workflows on IBM® quantum hardware using Qiskit Runtime primitives and sessions\n", + "\n", + "## Prerequisites\n", + "It is recommended that you familiarize yourself with these topics:\n", + "- [Basics of quantum information](/learning/courses/basics-of-quantum-information)\n", + "- [Introduction to Qiskit patterns](/docs/guides/intro-to-patterns)\n", + "- [Variational algorithm design](/learning/courses/variational-algorithm-design)\n", + "\n", "## Background\n", "\n", - "This tutorial shows how to build, deploy, and run a development workflow called a [Qiskit pattern](/docs/guides/intro-to-patterns) for simulating a Heisenberg chain and estimating its ground-state energy using the SPSA optimizer." + "The Heisenberg spin chain is one of the most widely studied models in condensed matter physics and quantum magnetism. It describes a one-dimensional lattice of interacting quantum spins, where nearest-neighbor spins are coupled through exchange interactions. The Hamiltonian for the isotropic Heisenberg model with an external magnetic field is given by:\n", + "\n", + "$$H = \\sum_{\\langle i,j \\rangle} \\left( J_x X_i X_j + J_y Y_i Y_j + J_z Z_i Z_j \\right) + \\sum_{i} h_i Z_i,$$\n", + "\n", + "where $X_i$, $Y_i$, and $Z_i$ are the Pauli operators acting on site $i$, the sum $\\langle i,j \\rangle$ runs over nearest-neighbor pairs, $J_x = J_y = J_z = 0.5$ are the exchange coupling constants (isotropic in this tutorial), and $h_i$ represents a site-dependent external magnetic field. In this tutorial, the magnetic field values are randomly sampled from the interval $[-1, 1]$. Note that in the implementation below, the set of \"nearest-neighbor\" pairs is determined by the hardware backend's native coupling among the first $N$ qubits, which might not form a strict linear chain depending on the device topology.\n", + "\n", + "Understanding the ground-state energy of this Hamiltonian is of fundamental importance in physics. The ground state encodes information about quantum phase transitions, entanglement structure, and magnetic ordering. Classically, computing the exact ground-state energy becomes intractable as the number of spins grows, since the Hilbert space dimension scales exponentially as $2^N$ for $N$ spins. This makes it a natural candidate for quantum simulation.\n", + "\n", + "The Variational Quantum Eigensolver (VQE) is a hybrid quantum-classical algorithm designed to estimate the ground-state energy of a Hamiltonian. It works by preparing a parameterized quantum state $|\\psi(\\theta)\\rangle$ (called an ansatz) on a quantum computer and measuring the expectation value $\\langle \\psi(\\theta) | H | \\psi(\\theta) \\rangle$. A classical optimizer then iteratively adjusts the parameters $\\theta$ to minimize this energy, leveraging the variational principle which guarantees that the measured energy is always an upper bound to the true ground-state energy.\n", + "\n", + "In this tutorial, we use the `efficient_su2` ansatz from Qiskit's circuit library, which constructs layers of single-qubit rotations and entangling gates. The optimization is carried out using the Simultaneous Perturbation Stochastic Approximation (SPSA) algorithm, which is well-suited for noisy quantum hardware because it estimates gradients using only two function evaluations per iteration regardless of the number of parameters." ] }, { @@ -38,8 +60,8 @@ "\n", "Before starting this tutorial, ensure that you have the following installed:\n", "\n", - "* Qiskit SDK v2.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n", - "* Qiskit Runtime v0.44 or later (`pip install qiskit-ibm-runtime`)" + "* Qiskit SDK v2.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n", + "* Qiskit Runtime v0.44 or later (`pip install qiskit-ibm-runtime`)" ] }, { @@ -52,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "id": "e7754922", "metadata": {}, "outputs": [], @@ -82,22 +104,32 @@ " plt.show()" ] }, + { + "cell_type": "markdown", + "id": "890d9c81", + "metadata": {}, + "source": [ + "## Small-scale example\n", + "\n", + "In this section, we walk through each step of the Qiskit pattern at a small scale, explaining the key components as we build up the workflow." + ] + }, { "cell_type": "markdown", "id": "132fb15f-10b4-4d7e-83d8-f512a6f675d1", "metadata": {}, "source": [ - "## Step 1: Map classical inputs to a quantum problem\n", + "### Step 1: Map classical inputs to a quantum problem\n", "\n", - "* Input: Number of spins\n", - "* Output: Ansatz and Hamiltonian modeling the Heisenberg chain\n", + "* Input: Number of spins\n", + "* Output: Ansatz and Hamiltonian modeling the Heisenberg chain\n", "\n", - "Construct an ansatz and Hamiltonian that model a 10-spin Heisenberg chain. First, we import some generic packages and create some helper functions." + "Construct an ansatz and Hamiltonian that model a 10-spin Heisenberg chain. In this step, we will build a 10-spin Heisenberg Hamiltonian over the least-busy backend's coupling map and prepare the `efficient_su2` ansatz." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1", "metadata": {}, "outputs": [ @@ -107,7 +139,7 @@ "\"Output" ] }, - "execution_count": 8, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -116,11 +148,7 @@ "num_spins = 10\n", "ansatz = efficient_su2(num_qubits=num_spins, reps=2)\n", "\n", - "service = QiskitRuntimeService(\n", - " channel=\"ibm_cloud\",\n", - " token=\"\", # Replace with your actual API token\n", - " instance=\"\", # Replace with your instance name if needed\n", - ")\n", + "service = QiskitRuntimeService()\n", "backend = service.least_busy(\n", " operational=True, min_num_qubits=num_spins, simulator=False\n", ")\n", @@ -149,17 +177,17 @@ "id": "ab79119b-5e56-49d8-a20e-1c8e665baec0", "metadata": {}, "source": [ - "## Step 2: Optimize problem for quantum hardware execution\n", + "### Step 2: Optimize problem for quantum hardware execution\n", "\n", - "* Input: Abstract circuit, observable\n", - "* Output: Target circuit and observable, optimized for the selected QPU\n", + "* Input: Abstract circuit, observable\n", + "* Output: Target circuit and observable, optimized for the selected QPU\n", "\n", "Use the `generate_preset_pass_manager` function from Qiskit to automatically generate an optimization routine for our circuit with respect to the selected QPU. We choose `optimization_level=3`, which provides the highest level of optimization of the preset pass managers. We also include `ALAPScheduleAnalysis` and `PadDynamicalDecoupling` scheduling passes to suppress decoherence errors." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "id": "a0a5f1c8-5c31-4d9f-ae81-37bd67271d44", "metadata": {}, "outputs": [ @@ -169,7 +197,7 @@ "\"Output" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -197,10 +225,10 @@ "id": "9e889d0b-30b5-4e6b-84c9-d1f096abf132", "metadata": {}, "source": [ - "## Step 3: Execute using Qiskit primitives\n", + "### Step 3: Execute using Qiskit primitives\n", "\n", - "* Input: Target circuit and observable\n", - "* Output: Results of optimization\n", + "* Input: Target circuit and observable\n", + "* Output: Results of optimization\n", "\n", "Minimize the estimated ground-state energy of the system by optimizing the circuit parameters. Use the `Estimator` primitive from Qiskit Runtime to evaluate the cost function during optimization.\n", "\n", @@ -218,16 +246,21 @@ "\n", "Simultaneous Perturbation Stochastic Approximation (SPSA) [\\[1\\]](#references) is an optimization algorithm that approximates the entire gradient vector using only two function calls at each iteration. Let $f:\\mathbb{R}^p\\rightarrow \\mathbb{R}$ be the cost function with $p$ parameters to be optimized, and $x_i\\in \\mathbb{R}^p$ be the parameter vector at the $i^{th}$ step of the iteration. To compute the gradient, a random vector $\\Delta_i$ of size $p$ is created, where each element $\\Delta_{ij}$, $\\forall$ $j\\in \\{1,2,...,p\\}$, is uniformly sampled from $\\{-1, 1\\}$. Next, each element of the random vector $\\Delta_i$ is multiplied with a small value $c_i$ to create a random perturbation. The gradient is then estimated as\n", "\n", + "\n", "$$[\\nabla f(x_i)]_j \\approx \\frac{f(x_i + c_i \\Delta_i) - f(x_i - c_i \\Delta_i)}{2c_i\\Delta_{ij}}.$$\n", "\n", "Intuitively, since a random perturbation is applied during the gradient estimation, it is expected that small deviations in the exact values of $f$ coming from noise can be tolerated and accounted for. In fact, SPSA is particularly known to be robust against noise, and requires only two hardware calls for each iteration. It is, therefore, one of the highly preferred optimizers for implementing variational algorithms.\n", "\n", - "In this tutorial, the hyperparameters for the $i^{th}$ iteration, $a_i$ and $c_i$, are computed as $a_i = a/(A + i + 1)^\\alpha$ and $c_i = c / (i+1)^\\gamma$, where the constant values are taken as $A = 30$, $\\alpha = 0.9$, $a = 0.3$, $c = 0.1$, and $\\gamma = 0.4$. These values are selected from [\\[2\\]](#references). Appropriate tuning of hyperparameters is necessary for extracting a good performance out of SPSA." + "In this tutorial, the hyperparameters for the $i^{th}$ iteration, $a_i$ and $c_i$, are computed as\n", + "\n", + "$$a_i = \\frac{a}{(A + i + 1)^\\alpha} \\quad \\text{and} \\quad c_i = \\frac{c}{(i+1)^\\gamma},$$\n", + "\n", + "where the constant values are taken as $A = 30$, $\\alpha = 0.9$, $a = 0.3$, $c = 0.1$, and $\\gamma = 0.4$. These values are selected from [\\[2\\]](#references). Appropriate tuning of hyperparameters is necessary for extracting a good performance out of SPSA." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "73a9352c", "metadata": {}, "outputs": [], @@ -256,7 +289,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "32ca3b6a", "metadata": {}, "outputs": [], @@ -297,6 +330,7 @@ " with Session(backend=backend) as session:\n", " estimator = EstimatorV2(mode=session)\n", " estimator.skip_transpilation = True\n", + " estimator.options.environment.job_tags = [\"TUT_HSVQE\"]\n", " x_opt = spsa(\n", " cost_func,\n", " x0=x0,\n", @@ -313,7 +347,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "f418b372", "metadata": {}, "outputs": [], @@ -333,7 +367,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "id": "1732ce37", "metadata": {}, "outputs": [ @@ -341,7 +375,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Fx Iters. done: 101 [Current cost: -2.19621]\r" + "Fx Iters. done: 101 [Current cost: -3.03843]" ] } ], @@ -357,15 +391,15 @@ "id": "33abbb3f-6245-4610-a05d-e2bc4cc551f0", "metadata": {}, "source": [ - "## Step 4: Post-process and return result in desired classical format\n", + "### Step 4: Post-process and return result in desired classical format\n", "\n", - "* Input: Ground-state energy estimates during optimization\n", - "* Output: Estimated ground-state energy" + "* Input: Ground-state energy estimates during optimization\n", + "* Output: Estimated ground-state energy" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "e5b58771-d543-4e75-9746-fbc7b28e4360", "metadata": {}, "outputs": [ @@ -373,7 +407,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Estimated ground state energy: [-2.19621239]\n" + "Estimated ground state energy: [-3.03842968]\n" ] } ], @@ -383,7 +417,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "ecd7762a", "metadata": {}, "outputs": [ @@ -405,6 +439,36 @@ "visualize_results(spsa_history)" ] }, + { + "cell_type": "markdown", + "id": "a3f4171f", + "metadata": {}, + "source": [ + "## Large-scale hardware example" + ] + }, + { + "cell_type": "markdown", + "id": "746e6133", + "metadata": {}, + "source": [ + "A large-scale hardware example is not included in this tutorial. As the number of qubits increases, VQE encounters significant challenges due to the [barren plateau](/learning/courses/variational-algorithm-design/optimization-loops#barren-plateaus) phenomenon: the gradient of the cost function vanishes exponentially with system size, making optimization practically infeasible for large circuits. Combined with hardware noise, this means that scaling VQE to larger spin chains does not produce reliably reproducible results. For approaches that overcome these limitations, see the Next Steps section below." + ] + }, + { + "cell_type": "markdown", + "id": "8f14492c", + "metadata": {}, + "source": [ + "## Challenge\n", + "\n", + "Now that you have a working VQE implementation for the Heisenberg chain, try the following:\n", + "\n", + "1. **Experiment with ansatz depth:** Modify the `reps` parameter in `efficient_su2` (for example, try `reps=1` and `reps=3`). How does ansatz depth affect the estimated ground-state energy and convergence speed? At what point do you observe diminishing returns or instability?\n", + "2. **Tune SPSA hyperparameters:** Adjust the learning rate schedule parameters (`a`, `c`, `alpha`, `gamma`, `A`) and observe how they impact convergence. Can you find a configuration that converges faster than the defaults used here?\n", + "3. **Compare coupling topologies:** Instead of using the backend's native coupling map, try constructing a simple nearest-neighbor linear chain and compare the results. How does the connectivity of the physical hardware affect the transpiled circuit depth and final energy estimate?" + ] + }, { "cell_type": "markdown", "id": "217a9379", @@ -412,24 +476,24 @@ "source": [ "## References\n", "\n", - "[1] Spall, J. C. (2002). Implementation of the simultaneous perturbation algorithm for stochastic optimization.\n", + "\\[1] Spall, J. C. (2002). Implementation of the simultaneous perturbation algorithm for stochastic optimization.\n", "IEEE Transactions on Aerospace and Electronic Systems, 34(3), 817-823.\n", "\n", - "[2] Sahin, M. Emre, et al. (2025). Qiskit Machine Learning: an open-source library for quantum machine learning tasks at scale on quantum hardware and classical simulators. arXiv:2505.17756." + "\\[2] Sahin, M. Emre, et al. (2025). Qiskit Machine Learning: an open-source library for quantum machine learning tasks at scale on quantum hardware and classical simulators. arXiv:2505.17756." ] }, { "cell_type": "markdown", - "id": "8f14492c", + "id": "8aefe54c", "metadata": {}, "source": [ "## Next steps\n", "\n", "\n", - "If you found this work interesting, you might be interested in the following material:\n", + " If you found this work interesting, you might be interested in the following material:\n", "\n", - "- Find the ground-state energy of a sparse Hamiltonian by following the [SQD tutorial](/docs/tutorials/sample-based-quantum-diagonalization)\n", - "- Take the [Variational algorithm design](/learning/courses/variational-algorithm-design) course in IBM Learning\n", + " * **Try Sample-based Quantum Diagonalization (SQD):** As demonstrated in this tutorial, VQE faces challenges at scale due to barren plateaus and high measurement overhead. IBM has developed [Sample-based Quantum Diagonalization (SQD)](https://www.ibm.com/quantum/blog/quantum-diagonalization) as a more scalable alternative. Unlike VQE, SQD avoids variational optimization entirely; instead, a quantum computer generates samples and a classical computer projects the Hamiltonian onto a subspace spanned by those samples and diagonalizes it. This provides an upper bound to the ground-state energy with significantly fewer measurements and without susceptibility to barren plateaus. Follow the [SQD tutorial](/docs/tutorials/sample-based-quantum-diagonalization) to see this approach in action.\n", + " * **Explore the Quantum Diagonalization Algorithms course:** Deepen your understanding of both VQE and SQD, including their trade-offs, in the [Quantum diagonalization algorithms](/learning/courses/quantum-diagonalization-algorithms) course on IBM Quantum Learning.\n", "" ] } diff --git a/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1-0.avif b/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1-0.avif index 55eb9e2315b..3659d935da1 100644 Binary files a/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1-0.avif and b/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1-0.avif differ diff --git a/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/a0a5f1c8-5c31-4d9f-ae81-37bd67271d44-0.avif b/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/a0a5f1c8-5c31-4d9f-ae81-37bd67271d44-0.avif index 1fce5821f8f..d59f916cc2b 100644 Binary files a/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/a0a5f1c8-5c31-4d9f-ae81-37bd67271d44-0.avif and b/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/a0a5f1c8-5c31-4d9f-ae81-37bd67271d44-0.avif differ diff --git a/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/ecd7762a-0.avif b/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/ecd7762a-0.avif index f6d142aadb3..0f03ae7af51 100644 Binary files a/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/ecd7762a-0.avif and b/public/docs/images/tutorials/spin-chain-vqe/extracted-outputs/ecd7762a-0.avif differ