From 0270ba15bd8d3844c533ba19ef9f2ca764df1c60 Mon Sep 17 00:00:00 2001 From: pablosuvi Date: Fri, 20 Mar 2026 10:57:02 +0000 Subject: [PATCH 1/8] Add notebook showing qiskit vqe? --- docs/source/tutorials/vqe_qiskit.ipynb | 246 +++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 docs/source/tutorials/vqe_qiskit.ipynb diff --git a/docs/source/tutorials/vqe_qiskit.ipynb b/docs/source/tutorials/vqe_qiskit.ipynb new file mode 100644 index 00000000..78cc222f --- /dev/null +++ b/docs/source/tutorials/vqe_qiskit.ipynb @@ -0,0 +1,246 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "56fc15e4", + "metadata": {}, + "source": [ + "# VQE for a spin model using `qse` Operators\n", + "\n", + "This notebook builds a spin model using the `qse` `Operator` / `Operators` classes,\n", + "converts it to a Qiskit `SparsePauliOp` via `to_qiskit()` method, and runs VQE to find the ground state energy." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "116e033e", + "metadata": {}, + "outputs": [], + "source": [ + "import qse \n", + "from qse.operator.operator import Operator\n", + "from qse.operator.operators import Operators\n" + ] + }, + { + "cell_type": "markdown", + "id": "7b142901", + "metadata": {}, + "source": [ + "## 1. Build the spin model.\n", + "\n", + "We build a 1D **transverse-field Ising model** (TFIM) on $N=10$ qubits:\n", + "\n", + "$$H = -J \\sum_{i=0}^{N-2} Z_i Z_{i+1} - h \\sum_{i=0}^{N-1} X_i$$" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b1ec8bad", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of qubits: 10\n", + "Number of terms: 19\n", + "\n", + "-1.00 Z0 Z1\n", + "-1.00 Z1 Z2\n", + "-1.00 Z2 Z3\n", + "-1.00 Z3 Z4\n", + "-1.00 Z4 Z5\n", + "-1.00 Z5 Z6\n", + "-1.00 Z6 Z7\n", + "-1.00 Z7 Z8\n", + "-1.00 Z8 Z9\n", + "-0.50 X0\n", + "-0.50 X1\n", + "-0.50 X2\n", + "-0.50 X3\n", + "-0.50 X4\n", + "-0.50 X5\n", + "-0.50 X6\n", + "-0.50 X7\n", + "-0.50 X8\n", + "-0.50 X9\n" + ] + } + ], + "source": [ + "N = 10 \n", + "J = 1.0 \n", + "h = 0.5 \n", + "op_list = []\n", + "\n", + "# ZZ interaction terms between neighbouring qubits \n", + "for i in range(N - 1):\n", + " op_list.append(\n", + " Operator([\"Z\", \"Z\"], [i, i+1], N, coef=-J)\n", + " )\n", + "\n", + "# Transverse field X terms on each qubit\n", + "for i in range(N):\n", + " op_list.append(\n", + " Operator(\"X\", i, N, coef=-h)\n", + " )\n", + "\n", + "H = Operators(op_list)\n", + "print(H)\n" + ] + }, + { + "cell_type": "markdown", + "id": "be80c5c1", + "metadata": {}, + "source": [ + "## 2. Convert to Qiskit `SparsePauliOp`\n", + "\n", + "Once we have the Hamiltonian $H$, we can use the `to_qiskit()` method to transform it to a Qiskit Sparse Pauli Operator. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "51b961bb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SparsePauliOp(['ZZIIIIIIII', 'IZZIIIIIII', 'IIZZIIIIII', 'IIIZZIIIII', 'IIIIZZIIII', 'IIIIIZZIII', 'IIIIIIZZII', 'IIIIIIIZZI', 'IIIIIIIIZZ', 'XIIIIIIIII', 'IXIIIIIIII', 'IIXIIIIIII', 'IIIXIIIIII', 'IIIIXIIIII', 'IIIIIXIIII', 'IIIIIIXIII', 'IIIIIIIXII', 'IIIIIIIIXI', 'IIIIIIIIIX'],\n", + " coeffs=[-1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j,\n", + " -1. +0.j, -1. +0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j,\n", + " -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j])\n" + ] + } + ], + "source": [ + "pauli_op = H.to_qiskit()\n", + "print(pauli_op)" + ] + }, + { + "cell_type": "markdown", + "id": "a006d641", + "metadata": {}, + "source": [ + "## 3. Set up and run VQE.\n", + "\n", + "We set up and run the VQE in qiskit. " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "7e8986ad", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.primitives import StatevectorEstimator\n", + "from qiskit.circuit.library import efficient_su2\n", + "\n", + "import numpy as np\n", + "from scipy.optimize import minimize" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55201685", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "VQE ground state energy : -9.745759\n" + ] + } + ], + "source": [ + "ansatz = efficient_su2(num_qubits=N, reps=2, entanglement=\"linear\")\n", + "estimator = StatevectorEstimator()\n", + "energies_list = []\n", + "def cost_function(params):\n", + " result = estimator.run([(ansatz, pauli_op, params)]).result()\n", + " energy = result[0].data.evs\n", + " energies_list.append(float(energy))\n", + " return float(energy)\n", + "\n", + "# Random initial parameters\n", + "rng = np.random.default_rng(42)\n", + "x0 = rng.uniform(-np.pi, np.pi, ansatz.num_parameters)\n", + "\n", + "result = minimize(\n", + " cost_function,\n", + " x0,\n", + " method=\"COBYLA\",\n", + " options={\"maxiter\": 2000, \"rhobeg\": 0.5}\n", + ")\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "94b26131", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "VQE ground state energy : -9.745759\n", + "Exact ground state energy: -9.76550395792718\n" + ] + } + ], + "source": [ + "ground_state = np.linalg.eigh(pauli_op.to_matrix())[0][0]\n", + "print(f\"VQE ground state energy : {result.fun:.6f}\")\n", + "print(f\"Exact ground state energy: {ground_state}\")" + ] + }, + { + "cell_type": "markdown", + "id": "ab8e9a6d", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87c3414d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env_qse", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From a4c0edab38b20657d0136119fce020b254238794 Mon Sep 17 00:00:00 2001 From: pablosuvi Date: Fri, 20 Mar 2026 11:00:53 +0000 Subject: [PATCH 2/8] Black formatting --- docs/source/tutorials/vqe_qiskit.ipynb | 40 +++++++++++--------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/docs/source/tutorials/vqe_qiskit.ipynb b/docs/source/tutorials/vqe_qiskit.ipynb index 78cc222f..2ec7a57f 100644 --- a/docs/source/tutorials/vqe_qiskit.ipynb +++ b/docs/source/tutorials/vqe_qiskit.ipynb @@ -18,9 +18,9 @@ "metadata": {}, "outputs": [], "source": [ - "import qse \n", + "import qse\n", "from qse.operator.operator import Operator\n", - "from qse.operator.operators import Operators\n" + "from qse.operator.operators import Operators" ] }, { @@ -71,25 +71,21 @@ } ], "source": [ - "N = 10 \n", - "J = 1.0 \n", - "h = 0.5 \n", + "N = 10\n", + "J = 1.0\n", + "h = 0.5\n", "op_list = []\n", "\n", - "# ZZ interaction terms between neighbouring qubits \n", + "# ZZ interaction terms between neighbouring qubits\n", "for i in range(N - 1):\n", - " op_list.append(\n", - " Operator([\"Z\", \"Z\"], [i, i+1], N, coef=-J)\n", - " )\n", + " op_list.append(Operator([\"Z\", \"Z\"], [i, i + 1], N, coef=-J))\n", "\n", "# Transverse field X terms on each qubit\n", "for i in range(N):\n", - " op_list.append(\n", - " Operator(\"X\", i, N, coef=-h)\n", - " )\n", + " op_list.append(Operator(\"X\", i, N, coef=-h))\n", "\n", "H = Operators(op_list)\n", - "print(H)\n" + "print(H)" ] }, { @@ -163,27 +159,25 @@ } ], "source": [ - "ansatz = efficient_su2(num_qubits=N, reps=2, entanglement=\"linear\")\n", + "ansatz = efficient_su2(num_qubits=N, reps=2, entanglement=\"linear\")\n", "estimator = StatevectorEstimator()\n", "energies_list = []\n", + "\n", + "\n", "def cost_function(params):\n", " result = estimator.run([(ansatz, pauli_op, params)]).result()\n", " energy = result[0].data.evs\n", " energies_list.append(float(energy))\n", " return float(energy)\n", "\n", + "\n", "# Random initial parameters\n", - "rng = np.random.default_rng(42)\n", - "x0 = rng.uniform(-np.pi, np.pi, ansatz.num_parameters)\n", + "rng = np.random.default_rng(42)\n", + "x0 = rng.uniform(-np.pi, np.pi, ansatz.num_parameters)\n", "\n", "result = minimize(\n", - " cost_function,\n", - " x0,\n", - " method=\"COBYLA\",\n", - " options={\"maxiter\": 2000, \"rhobeg\": 0.5}\n", - ")\n", - "\n", - "\n" + " cost_function, x0, method=\"COBYLA\", options={\"maxiter\": 2000, \"rhobeg\": 0.5}\n", + ")" ] }, { From 4c8e4c5d90ff7ad419426cedb38250eb7736fb3b Mon Sep 17 00:00:00 2001 From: pablosuvi Date: Tue, 24 Mar 2026 08:47:56 +0000 Subject: [PATCH 3/8] Use compute_interaction_hamiltonian function for Hamiltonian computation --- docs/source/tutorials/vqe_qiskit.ipynb | 71 +++++++------------------- 1 file changed, 18 insertions(+), 53 deletions(-) diff --git a/docs/source/tutorials/vqe_qiskit.ipynb b/docs/source/tutorials/vqe_qiskit.ipynb index 2ec7a57f..a7a3ba73 100644 --- a/docs/source/tutorials/vqe_qiskit.ipynb +++ b/docs/source/tutorials/vqe_qiskit.ipynb @@ -13,11 +13,12 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 3, "id": "116e033e", "metadata": {}, "outputs": [], "source": [ + "import numpy as np \n", "import qse\n", "from qse.operator.operator import Operator\n", "from qse.operator.operators import Operators" @@ -37,55 +38,27 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 4, "id": "b1ec8bad", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of qubits: 10\n", - "Number of terms: 19\n", - "\n", - "-1.00 Z0 Z1\n", - "-1.00 Z1 Z2\n", - "-1.00 Z2 Z3\n", - "-1.00 Z3 Z4\n", - "-1.00 Z4 Z5\n", - "-1.00 Z5 Z6\n", - "-1.00 Z6 Z7\n", - "-1.00 Z7 Z8\n", - "-1.00 Z8 Z9\n", - "-0.50 X0\n", - "-0.50 X1\n", - "-0.50 X2\n", - "-0.50 X3\n", - "-0.50 X4\n", - "-0.50 X5\n", - "-0.50 X6\n", - "-0.50 X7\n", - "-0.50 X8\n", - "-0.50 X9\n" - ] - } - ], + "outputs": [], "source": [ "N = 10\n", "J = 1.0\n", "h = 0.5\n", - "op_list = []\n", + "spacing = 1.0\n", + "\n", + "qbits = qse.lattices.chain(spacing, N)\n", "\n", "# ZZ interaction terms between neighbouring qubits\n", - "for i in range(N - 1):\n", - " op_list.append(Operator([\"Z\", \"Z\"], [i, i + 1], N, coef=-J))\n", + "hamiltonian = qbits.compute_interaction_hamiltonian(\n", + " distance_func=lambda d: -J * np.isclose(d, spacing), \n", + " interaction=\"Z\",\n", + " )\n", "\n", "# Transverse field X terms on each qubit\n", "for i in range(N):\n", - " op_list.append(Operator(\"X\", i, N, coef=-h))\n", - "\n", - "H = Operators(op_list)\n", - "print(H)" + " hamiltonian += qse.Operator(\"X\", i, N, coef=-h)" ] }, { @@ -100,7 +73,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 5, "id": "51b961bb", "metadata": {}, "outputs": [ @@ -116,7 +89,7 @@ } ], "source": [ - "pauli_op = H.to_qiskit()\n", + "pauli_op = hamiltonian.to_qiskit()\n", "print(pauli_op)" ] }, @@ -132,7 +105,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 6, "id": "7e8986ad", "metadata": {}, "outputs": [], @@ -146,18 +119,10 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "55201685", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "VQE ground state energy : -9.745759\n" - ] - } - ], + "outputs": [], "source": [ "ansatz = efficient_su2(num_qubits=N, reps=2, entanglement=\"linear\")\n", "estimator = StatevectorEstimator()\n", @@ -182,7 +147,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 8, "id": "94b26131", "metadata": {}, "outputs": [ From b27e361fb53b30b9e8063e020174ecbd77932097 Mon Sep 17 00:00:00 2001 From: pablosuvi Date: Tue, 24 Mar 2026 08:50:50 +0000 Subject: [PATCH 4/8] Add qiskit to the docs dependancies list in pyproject.toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index bcb176b7..10157675 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ docs = [ "sphinx-copybutton", "tomli", "pulser", # required for creating the docs + "qiskit" ] [tool.black] From dabe5a6fe36a70a97a6023c1c3517933174d9b74 Mon Sep 17 00:00:00 2001 From: pablosuvi Date: Tue, 24 Mar 2026 09:06:32 +0000 Subject: [PATCH 5/8] Add tutorial to docs index --- docs/source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/index.rst b/docs/source/index.rst index 5d9b5dcb..f6f0ab57 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -33,6 +33,7 @@ See the `contributing page Date: Tue, 24 Mar 2026 09:16:15 +0000 Subject: [PATCH 6/8] Black formatting --- docs/source/tutorials/vqe_qiskit.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/tutorials/vqe_qiskit.ipynb b/docs/source/tutorials/vqe_qiskit.ipynb index a7a3ba73..d630b687 100644 --- a/docs/source/tutorials/vqe_qiskit.ipynb +++ b/docs/source/tutorials/vqe_qiskit.ipynb @@ -18,7 +18,7 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np \n", + "import numpy as np\n", "import qse\n", "from qse.operator.operator import Operator\n", "from qse.operator.operators import Operators" @@ -52,9 +52,9 @@ "\n", "# ZZ interaction terms between neighbouring qubits\n", "hamiltonian = qbits.compute_interaction_hamiltonian(\n", - " distance_func=lambda d: -J * np.isclose(d, spacing), \n", + " distance_func=lambda d: -J * np.isclose(d, spacing),\n", " interaction=\"Z\",\n", - " )\n", + ")\n", "\n", "# Transverse field X terms on each qubit\n", "for i in range(N):\n", From 4fcb620090d48df4a40a11ad851654bb3689bcb1 Mon Sep 17 00:00:00 2001 From: pablosuvi Date: Tue, 24 Mar 2026 09:41:49 +0000 Subject: [PATCH 7/8] Undo changes in index.rst to avoid conflicts --- docs/source/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index f6f0ab57..5d9b5dcb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -33,7 +33,6 @@ See the `contributing page Date: Tue, 21 Apr 2026 16:27:25 +0100 Subject: [PATCH 8/8] Add vqe qiskit tutorial to _toc.yml file --- docs/_toc.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_toc.yml b/docs/_toc.yml index 16c4da32..ff2049bd 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -11,6 +11,7 @@ parts: - file: tutorials/generating_lattices - file: tutorials/pulser-calc-example - file: tutorials/finite-geometries + - file: tutorials/vqe_qiskit - caption: Use-Cases chapters: - file: use-cases/ssh_model