Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 106 additions & 42 deletions docs/tutorials/spin-chain-vqe.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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."
]
},
{
Expand All @@ -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`)"
]
},
{
Expand All @@ -52,7 +74,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"id": "e7754922",
"metadata": {},
"outputs": [],
Expand Down Expand Up @@ -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": [
Expand All @@ -107,7 +139,7 @@
"<Image src=\"/docs/images/tutorials/spin-chain-vqe/extracted-outputs/7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 8,
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -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=\"<YOUR_API_TOKEN>\", # Replace with your actual API token\n",
" instance=\"<YOUR_INSTANCE_NAME>\", # 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",
Expand Down Expand Up @@ -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": [
Expand All @@ -169,7 +197,7 @@
"<Image src=\"/docs/images/tutorials/spin-chain-vqe/extracted-outputs/a0a5f1c8-5c31-4d9f-ae81-37bd67271d44-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 5,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -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",
Expand All @@ -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": [],
Expand Down Expand Up @@ -256,7 +289,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 8,
"id": "32ca3b6a",
"metadata": {},
"outputs": [],
Expand Down Expand Up @@ -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",
Expand All @@ -313,7 +347,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 9,
"id": "f418b372",
"metadata": {},
"outputs": [],
Expand All @@ -333,15 +367,15 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 10,
"id": "1732ce37",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fx Iters. done: 101 [Current cost: -2.19621]\r"
"Fx Iters. done: 101 [Current cost: -3.03843]"
]
}
],
Expand All @@ -357,23 +391,23 @@
"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": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Estimated ground state energy: [-2.19621239]\n"
"Estimated ground state energy: [-3.03842968]\n"
]
}
],
Expand All @@ -383,7 +417,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 12,
"id": "ecd7762a",
"metadata": {},
"outputs": [
Expand All @@ -405,31 +439,61 @@
"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",
"metadata": {},
"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",
"<Admonition type=\"tip\" title=\"Recommendations\">\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",
"</Admonition>"
]
}
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading