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