diff --git a/docs/tutorials/sample-based-krylov-quantum-diagonalization.ipynb b/docs/tutorials/sample-based-krylov-quantum-diagonalization.ipynb
index 60a4bc25c3f..d36bcf67877 100644
--- a/docs/tutorials/sample-based-krylov-quantum-diagonalization.ipynb
+++ b/docs/tutorials/sample-based-krylov-quantum-diagonalization.ipynb
@@ -18,6 +18,24 @@
"*Usage estimate: Nine seconds on a Heron r2 processor (NOTE: This is an estimate only. Your runtime might vary.)*"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "metadata": {},
+ "source": [
+ "## Learning outcomes\n",
+ "After going through this tutorial, users should understand:\n",
+ "- How to use the [SQD Qiskit addon](https://github.com/Qiskit/qiskit-addon-sqd) to approximate the ground state energy of a lattice model using bitstrings sampled from a quantum processing unit (QPU).\n",
+ "- How to use [ffsim](https://github.com/qiskit-community/ffsim) to construct time evolution circuits for fermionic simulation.\n",
+ "- How to combine samples from multiple circuits for post-processing with the sample-based Krylov diagonalization (SKQD) algorithm.\n",
+ "\n",
+ "## Prerequisites\n",
+ "We suggest that users are familiar with the following topics before going through this tutorial:\n",
+ "- [Sample-based quantum diagonalization of a chemistry Hamiltonian](/docs/tutorials/sample-based-quantum-diagonalization)\n",
+ "- [Krylov quantum diagonalization of lattice Hamiltonians](/docs/tutorials/krylov-quantum-diagonalization)\n",
+ "- [Qiskit primitives](/docs/guides/get-started-with-primitives)"
+ ]
+ },
{
"cell_type": "markdown",
"id": "dc5cc74e-06bf-45ac-a69b-81778138e08f",
@@ -104,7 +122,15 @@
"- Qiskit SDK v1.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n",
"- Qiskit Runtime v0.22 or later (`pip install qiskit-ibm-runtime`)\n",
"- SQD Qiskit addon v0.11 or later (`pip install qiskit-addon-sqd`)\n",
- "- ffsim (`pip install ffsim`)"
+ "- ffsim v0.0.72 or later (`pip install ffsim`)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
+ "metadata": {},
+ "source": [
+ "## Small-scale simulator example"
]
},
{
@@ -112,7 +138,7 @@
"id": "8540487a-8033-49c2-9f30-022336105f64",
"metadata": {},
"source": [
- "## Step 1: Map problem to a quantum circuit"
+ "### Step 1: Map problem to a quantum circuit"
]
},
{
@@ -131,6 +157,7 @@
"outputs": [],
"source": [
"import numpy as np\n",
+ "import pyscf.fci\n",
"\n",
"\n",
"def siam_hamiltonian(\n",
@@ -208,7 +235,7 @@
"\n",
"# Total number of spatial orbitals, including the bath sites and the impurity\n",
"# This should be an even number\n",
- "norb = 20\n",
+ "norb = 8\n",
"\n",
"# System is half-filled\n",
"nelec = (norb // 2, norb // 2)\n",
@@ -234,7 +261,10 @@
"orbital_rotation = momentum_basis(norb)\n",
"h1e_momentum, h2e_momentum = rotated(h1e, h2e, orbital_rotation.T.conj())\n",
"# In the momentum basis, the impurity is placed in the center\n",
- "impurity_index = n_bath // 2"
+ "impurity_index = n_bath // 2\n",
+ "\n",
+ "# Use PySCF to compute the exact ground state energy\n",
+ "reference_energy, _ = pyscf.fci.direct_spin1.kernel(h1e, h2e, norb, nelec)"
]
},
{
@@ -267,6 +297,7 @@
"\n",
"def prepare_initial_state(qubits: Sequence[Qubit], norb: int, nocc: int):\n",
" \"\"\"Prepare initial state.\"\"\"\n",
+ " assert norb >= 8\n",
" x_gate = XGate()\n",
" rot = XXPlusYYGate(0.5 * np.pi, -0.5 * np.pi)\n",
" for i in range(nocc):\n",
@@ -398,7 +429,7 @@
"id": "b8ca6be4-61d9-47be-8099-8712c7ecc774",
"metadata": {},
"source": [
- "## Step 2: Optimize problem for quantum execution"
+ "### Step 2: Optimize problem for quantum execution"
]
},
{
@@ -406,7 +437,7 @@
"id": "a3304e1b-9c7c-4212-8744-d1c62292eced",
"metadata": {},
"source": [
- "Now that we have created the circuits, we can optimize them for a target hardware. We pick the least busy QPU with at least 127 qubits. Check out the [Qiskit IBM® Runtime docs](/docs/guides/get-started-with-primitives#get-started-with-sampler) for more information."
+ "Next, we optimize the circuit for a target hardware. For now, we'll create a generic backend with a specified number of qubits and a gate set that the time evolution circuits naturally decompose to."
]
},
{
@@ -414,23 +445,13 @@
"execution_count": 5,
"id": "2d2fdbff-1e22-45af-a2eb-c334e4328c59",
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Using backend ibm_fez\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
- "from qiskit_ibm_runtime import QiskitRuntimeService\n",
+ "from qiskit.providers.fake_provider import GenericBackendV2\n",
"\n",
- "service = QiskitRuntimeService()\n",
- "backend = service.least_busy(\n",
- " operational=True, simulator=False, min_num_qubits=127\n",
- ")\n",
- "print(f\"Using backend {backend.name}\")"
+ "backend = GenericBackendV2(\n",
+ " 2 * norb, basis_gates=[\"cp\", \"xx_plus_yy\", \"p\", \"x\"]\n",
+ ")"
]
},
{
@@ -461,7 +482,7 @@
"id": "6cfd3eea-e2d9-40a5-a449-1d3d790a5f2d",
"metadata": {},
"source": [
- "## Step 3: Execute by using Qiskit primitives"
+ "### Step 3: Execute by using Qiskit primitives"
]
},
{
@@ -477,13 +498,22 @@
"execution_count": 7,
"id": "80eee553-60d6-4258-88ab-d8d120418c36",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/kjs/projects/documentation/.venv/lib/python3.12/site-packages/qiskit/circuit/quantumcircuit.py:4625: UserWarning: Trying to add QuantumRegister to a QuantumCircuit having a layout\n",
+ " circ.add_register(qreg)\n"
+ ]
+ }
+ ],
"source": [
"from qiskit.visualization import plot_histogram\n",
- "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
+ "from qiskit.primitives import StatevectorSampler\n",
"\n",
"# Sample from the circuits\n",
- "sampler = Sampler(backend)\n",
+ "sampler = StatevectorSampler()\n",
"job = sampler.run(isa_circuits, shots=500)"
]
},
@@ -507,7 +537,7 @@
"source": [
"from qiskit.primitives import BitArray\n",
"\n",
- "# Combine the counts from the individual Trotter circuits\n",
+ "# Combine the shots from the individual Trotter circuits\n",
"bit_array = BitArray.concatenate_shots(\n",
" [result.data.meas for result in job.result()]\n",
")\n",
@@ -520,7 +550,7 @@
"id": "2aa74455-d16b-4ac3-a354-54a79d5c5759",
"metadata": {},
"source": [
- "## Step 4: Post-process and return result to desired classical format"
+ "### Step 4: Post-process and return result to desired classical format"
]
},
{
@@ -543,54 +573,44 @@
"text": [
"Iteration 1\n",
"\tSubsample 0\n",
- "\t\tEnergy: -28.61321893815165\n",
- "\t\tSubspace dimension: 10609\n",
+ "\t\tEnergy: -13.4222953188441\n",
+ "\t\tSubspace dimension: 529\n",
"\tSubsample 1\n",
- "\t\tEnergy: -28.628985564542244\n",
- "\t\tSubspace dimension: 13924\n",
+ "\t\tEnergy: -13.42237556285828\n",
+ "\t\tSubspace dimension: 784\n",
"\tSubsample 2\n",
- "\t\tEnergy: -28.620151775558114\n",
- "\t\tSubspace dimension: 10404\n",
+ "\t\tEnergy: -13.422045397387413\n",
+ "\t\tSubspace dimension: 529\n",
"Iteration 2\n",
"\tSubsample 0\n",
- "\t\tEnergy: -28.656893066053115\n",
- "\t\tSubspace dimension: 34225\n",
+ "\t\tEnergy: -13.422379583305478\n",
+ "\t\tSubspace dimension: 900\n",
"\tSubsample 1\n",
- "\t\tEnergy: -28.65277622004119\n",
- "\t\tSubspace dimension: 38416\n",
+ "\t\tEnergy: -13.422376197704326\n",
+ "\t\tSubspace dimension: 841\n",
"\tSubsample 2\n",
- "\t\tEnergy: -28.670856034959165\n",
- "\t\tSubspace dimension: 39601\n",
+ "\t\tEnergy: -13.422421162849295\n",
+ "\t\tSubspace dimension: 1089\n",
"Iteration 3\n",
"\tSubsample 0\n",
- "\t\tEnergy: -28.684787675404362\n",
- "\t\tSubspace dimension: 42436\n",
+ "\t\tEnergy: -13.422421164670345\n",
+ "\t\tSubspace dimension: 1156\n",
"\tSubsample 1\n",
- "\t\tEnergy: -28.676984757118426\n",
- "\t\tSubspace dimension: 50176\n",
+ "\t\tEnergy: -13.422421492737689\n",
+ "\t\tSubspace dimension: 1156\n",
"\tSubsample 2\n",
- "\t\tEnergy: -28.671581704249885\n",
- "\t\tSubspace dimension: 40804\n",
+ "\t\tEnergy: -13.422421205869572\n",
+ "\t\tSubspace dimension: 1156\n",
"Iteration 4\n",
"\tSubsample 0\n",
- "\t\tEnergy: -28.6859683054753\n",
- "\t\tSubspace dimension: 47961\n",
+ "\t\tEnergy: -13.422421494558726\n",
+ "\t\tSubspace dimension: 1225\n",
"\tSubsample 1\n",
- "\t\tEnergy: -28.69418206537316\n",
- "\t\tSubspace dimension: 51529\n",
+ "\t\tEnergy: -13.422421492737689\n",
+ "\t\tSubspace dimension: 1156\n",
"\tSubsample 2\n",
- "\t\tEnergy: -28.686083516445752\n",
- "\t\tSubspace dimension: 51529\n",
- "Iteration 5\n",
- "\tSubsample 0\n",
- "\t\tEnergy: -28.694665630711178\n",
- "\t\tSubspace dimension: 50625\n",
- "\tSubsample 1\n",
- "\t\tEnergy: -28.69505984237118\n",
- "\t\tSubspace dimension: 47524\n",
- "\tSubsample 2\n",
- "\t\tEnergy: -28.6942873883992\n",
- "\t\tSubspace dimension: 48841\n"
+ "\t\tEnergy: -13.422421492737689\n",
+ "\t\tSubspace dimension: 1156\n"
]
}
],
@@ -637,7 +657,7 @@
"id": "3dee9c61-fc42-48e9-8888-af8fc831cd5c",
"metadata": {},
"source": [
- "The following code cell plots the results. The first plot shows the computed energy as a function of the number of configuration recovery iterations, and the second plot shows the average occupancy of each spatial orbital after the final iteration. For the reference energy, we use the results of a [DMRG](https://en.wikipedia.org/wiki/Density_matrix_renormalization_group) calculation that was performed separately."
+ "The following code cell plots the results. The first plot shows the computed energy as a function of the number of configuration recovery iterations, and the second plot shows the average occupancy of each spatial orbital after the final iteration. Since this is such a small problem, the first iteration already brings us very close to the exact energy (note the scale of the y axis)."
]
},
{
@@ -650,9 +670,9 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Reference (DMRG) energy: -28.70660\n",
- "SQD energy: -28.69506\n",
- "Absolute error: 0.01154\n"
+ "Reference energy: -13.42249\n",
+ "SQD energy: -13.42242\n",
+ "Absolute error: 0.00007\n"
]
},
{
@@ -668,8 +688,6 @@
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
- "dmrg_energy = -28.70659686\n",
- "\n",
"min_es = [\n",
" min(result, key=lambda res: res.energy).energy\n",
" for result in result_history\n",
@@ -690,7 +708,10 @@
"axs[0].set_xticks(x1)\n",
"axs[0].set_xticklabels(x1)\n",
"axs[0].axhline(\n",
- " y=dmrg_energy, color=\"#BF5700\", linestyle=\"--\", label=\"DMRG energy\"\n",
+ " y=reference_energy,\n",
+ " color=\"#BF5700\",\n",
+ " linestyle=\"--\",\n",
+ " label=\"reference energy\",\n",
")\n",
"axs[0].set_title(\"Approximated Ground State Energy vs SQD Iterations\")\n",
"axs[0].set_xlabel(\"Iteration Index\", fontdict={\"fontsize\": 12})\n",
@@ -705,9 +726,9 @@
"axs[1].set_xlabel(\"Orbital Index\", fontdict={\"fontsize\": 12})\n",
"axs[1].set_ylabel(\"Avg Occupancy\", fontdict={\"fontsize\": 12})\n",
"\n",
- "print(f\"Reference (DMRG) energy: {dmrg_energy:.5f}\")\n",
+ "print(f\"Reference energy: {reference_energy:.5f}\")\n",
"print(f\"SQD energy: {min_e:.5f}\")\n",
- "print(f\"Absolute error: {abs(min_e - dmrg_energy):.5f}\")\n",
+ "print(f\"Absolute error: {abs(min_e - reference_energy):.5f}\")\n",
"plt.tight_layout()\n",
"plt.show()"
]
@@ -732,7 +753,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Recomputed energy: -28.69506\n"
+ "Recomputed energy: -13.42242\n"
]
}
],
@@ -747,14 +768,248 @@
},
{
"cell_type": "markdown",
- "id": "482ebea3-84b8-471b-bddc-b282e23162ad",
+ "id": "5221928a-79ff-4f54-90b4-1fe4d7739aae",
"metadata": {},
"source": [
- "## References\n",
+ "## Large-scale hardware example\n",
+ "\n",
+ "Now, we run a larger example on a real QPU.\n",
+ "For the reference energy, we use the results of a [DMRG](https://en.wikipedia.org/wiki/Density_matrix_renormalization_group) calculation that was performed separately."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "933037d8-847e-4986-80da-5ac8d677b2ff",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Using backend ibm_boston\n",
+ "Iteration 1\n",
+ "\tSubsample 0\n",
+ "\t\tEnergy: -28.63965951544449\n",
+ "\t\tSubspace dimension: 9801\n",
+ "\tSubsample 1\n",
+ "\t\tEnergy: -28.625588929202006\n",
+ "\t\tSubspace dimension: 9409\n",
+ "\tSubsample 2\n",
+ "\t\tEnergy: -28.647371834135498\n",
+ "\t\tSubspace dimension: 8281\n",
+ "Iteration 2\n",
+ "\tSubsample 0\n",
+ "\t\tEnergy: -28.67213260849567\n",
+ "\t\tSubspace dimension: 29584\n",
+ "\tSubsample 1\n",
+ "\t\tEnergy: -28.670340686158816\n",
+ "\t\tSubspace dimension: 27225\n",
+ "\tSubsample 2\n",
+ "\t\tEnergy: -28.669976379525988\n",
+ "\t\tSubspace dimension: 31329\n",
+ "Iteration 3\n",
+ "\tSubsample 0\n",
+ "\t\tEnergy: -28.68622875601382\n",
+ "\t\tSubspace dimension: 36100\n",
+ "\tSubsample 1\n",
+ "\t\tEnergy: -28.698569623143126\n",
+ "\t\tSubspace dimension: 34225\n",
+ "\tSubsample 2\n",
+ "\t\tEnergy: -28.694848533971882\n",
+ "\t\tSubspace dimension: 33856\n",
+ "Iteration 4\n",
+ "\tSubsample 0\n",
+ "\t\tEnergy: -28.69883392844593\n",
+ "\t\tSubspace dimension: 42025\n",
+ "\tSubsample 1\n",
+ "\t\tEnergy: -28.701289495200996\n",
+ "\t\tSubspace dimension: 38025\n",
+ "\tSubsample 2\n",
+ "\t\tEnergy: -28.699319594978245\n",
+ "\t\tSubspace dimension: 45369\n",
+ "Iteration 5\n",
+ "\tSubsample 0\n",
+ "\t\tEnergy: -28.701936886834154\n",
+ "\t\tSubspace dimension: 51076\n",
+ "\tSubsample 1\n",
+ "\t\tEnergy: -28.702468711812013\n",
+ "\t\tSubspace dimension: 53824\n",
+ "\tSubsample 2\n",
+ "\t\tEnergy: -28.702298147575938\n",
+ "\t\tSubspace dimension: 52900\n",
+ "Reference energy: -28.70660\n",
+ "SQD energy: -28.70247\n",
+ "Absolute error: 0.00413\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
+ "from qiskit_ibm_runtime import QiskitRuntimeService\n",
"\n",
- "- [Quantum-Centric Algorithm for Sample-Based Krylov Diagonalization (SKQD paper)](https://arxiv.org/abs/2501.09702)\n",
- "- [Chemistry Beyond Exact Solutions on a Quantum-Centric Supercomputer (SQD paper)](https://arxiv.org/abs/2405.05068)\n",
- "- [Diagonalization of large many-body Hamiltonians on a quantum processor (KQD paper)](https://arxiv.org/abs/2407.14431)"
+ "# Model parameters\n",
+ "norb = 20\n",
+ "nelec = (norb // 2, norb // 2)\n",
+ "n_bath = norb - 1\n",
+ "hybridization = 1.0\n",
+ "hopping = 1.0\n",
+ "onsite = 10.0\n",
+ "chemical_potential = -0.5 * onsite\n",
+ "\n",
+ "# Generate Hamiltonian and orbital rotation\n",
+ "h1e, h2e = siam_hamiltonian(\n",
+ " norb=norb,\n",
+ " hopping=hopping,\n",
+ " onsite=onsite,\n",
+ " hybridization=hybridization,\n",
+ " chemical_potential=chemical_potential,\n",
+ ")\n",
+ "orbital_rotation = momentum_basis(norb)\n",
+ "h1e_momentum, h2e_momentum = rotated(h1e, h2e, orbital_rotation.T.conj())\n",
+ "impurity_index = n_bath // 2\n",
+ "\n",
+ "# Set reference energy to DMRG value computed separately\n",
+ "reference_energy = -28.70659686\n",
+ "\n",
+ "# Algorithm parameters\n",
+ "time_step = 0.2\n",
+ "krylov_dim = 8\n",
+ "\n",
+ "# Construct circuits\n",
+ "qubits = QuantumRegister(2 * norb, name=\"q\")\n",
+ "circuit = QuantumCircuit(qubits)\n",
+ "for instruction in prepare_initial_state(qubits, norb=norb, nocc=norb // 2):\n",
+ " circuit.append(instruction)\n",
+ "circuit.measure_all()\n",
+ "circuits = [circuit.copy()]\n",
+ "one_body_evolution = scipy.linalg.expm(-1j * time_step * h1e_momentum)\n",
+ "for i in range(krylov_dim - 1):\n",
+ " circuit.remove_final_measurements()\n",
+ " for instruction in trotter_step(\n",
+ " qubits,\n",
+ " time_step,\n",
+ " one_body_evolution,\n",
+ " h2e_momentum,\n",
+ " impurity_index,\n",
+ " norb,\n",
+ " ):\n",
+ " circuit.append(instruction)\n",
+ " circuit.measure_all()\n",
+ " circuits.append(circuit.copy())\n",
+ "\n",
+ "# Initialize hardware backend\n",
+ "service = QiskitRuntimeService()\n",
+ "backend = service.least_busy(\n",
+ " operational=True, simulator=False, min_num_qubits=127\n",
+ ")\n",
+ "print(f\"Using backend {backend.name}\")\n",
+ "\n",
+ "# Transpile to backend\n",
+ "pass_manager = generate_preset_pass_manager(\n",
+ " optimization_level=3, backend=backend\n",
+ ")\n",
+ "isa_circuits = pass_manager.run(circuits)\n",
+ "\n",
+ "# Sample from the circuits\n",
+ "sampler = Sampler(backend)\n",
+ "job = sampler.run(isa_circuits, shots=500)\n",
+ "\n",
+ "# Combine the shots from the individual Trotter circuits\n",
+ "bit_array = BitArray.concatenate_shots(\n",
+ " [result.data.meas for result in job.result()]\n",
+ ")\n",
+ "\n",
+ "# Run configuration recovery and diagonalization\n",
+ "result_history = []\n",
+ "\n",
+ "\n",
+ "def callback(results: list[SCIResult]):\n",
+ " result_history.append(results)\n",
+ " iteration = len(result_history)\n",
+ " print(f\"Iteration {iteration}\")\n",
+ " for i, result in enumerate(results):\n",
+ " print(f\"\\tSubsample {i}\")\n",
+ " print(f\"\\t\\tEnergy: {result.energy}\")\n",
+ " print(\n",
+ " f\"\\t\\tSubspace dimension: {np.prod(result.sci_state.amplitudes.shape)}\"\n",
+ " )\n",
+ "\n",
+ "\n",
+ "rng = np.random.default_rng(24)\n",
+ "result = diagonalize_fermionic_hamiltonian(\n",
+ " h1e_momentum,\n",
+ " h2e_momentum,\n",
+ " bit_array,\n",
+ " samples_per_batch=100,\n",
+ " norb=norb,\n",
+ " nelec=nelec,\n",
+ " num_batches=3,\n",
+ " max_iterations=5,\n",
+ " symmetrize_spin=True,\n",
+ " callback=callback,\n",
+ " seed=rng,\n",
+ ")\n",
+ "\n",
+ "\n",
+ "# Plot results\n",
+ "min_es = [\n",
+ " min(result, key=lambda res: res.energy).energy\n",
+ " for result in result_history\n",
+ "]\n",
+ "min_id, min_e = min(enumerate(min_es), key=lambda x: x[1])\n",
+ "x1 = range(len(result_history))\n",
+ "y2 = np.sum(result.orbital_occupancies, axis=0)\n",
+ "x2 = range(len(y2))\n",
+ "fig, axs = plt.subplots(1, 2, figsize=(12, 6))\n",
+ "axs[0].plot(x1, min_es, label=\"energy\", marker=\"o\")\n",
+ "axs[0].set_xticks(x1)\n",
+ "axs[0].set_xticklabels(x1)\n",
+ "axs[0].axhline(\n",
+ " y=reference_energy,\n",
+ " color=\"#BF5700\",\n",
+ " linestyle=\"--\",\n",
+ " label=\"reference energy\",\n",
+ ")\n",
+ "axs[0].set_title(\"Approximated Ground State Energy vs SQD Iterations\")\n",
+ "axs[0].set_xlabel(\"Iteration Index\", fontdict={\"fontsize\": 12})\n",
+ "axs[0].set_ylabel(\"Energy\", fontdict={\"fontsize\": 12})\n",
+ "axs[0].legend()\n",
+ "axs[1].bar(x2, y2, width=0.8)\n",
+ "axs[1].set_xticks(x2)\n",
+ "axs[1].set_xticklabels(x2)\n",
+ "axs[1].set_title(\"Avg Occupancy per Spatial Orbital\")\n",
+ "axs[1].set_xlabel(\"Orbital Index\", fontdict={\"fontsize\": 12})\n",
+ "axs[1].set_ylabel(\"Avg Occupancy\", fontdict={\"fontsize\": 12})\n",
+ "print(f\"Reference energy: {reference_energy:.5f}\")\n",
+ "print(f\"SQD energy: {min_e:.5f}\")\n",
+ "print(f\"Absolute error: {abs(min_e - reference_energy):.5f}\")\n",
+ "plt.tight_layout()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "482ebea3-84b8-471b-bddc-b282e23162ad",
+ "metadata": {},
+ "source": [
+ "## Next steps\n",
+ "If you found this work interesting, you might be interested in the following material:\n",
+ "\n",
+ "- [Sample-based quantum diagonalization of a chemistry Hamiltonian](/docs/tutorials/sample-based-quantum-diagonalization) - a related tutorial using a heuristic variational ansatz instead of Trotter circuits\n",
+ "- [Krylov quantum diagonalization of lattice Hamiltonians](/docs/tutorials/krylov-quantum-diagonalization) - a tutorial on the KQD method\n",
+ "- [SQD addon API documentation](https://qiskit.github.io/qiskit-addon-sqd/apidocs/qiskit_addon_sqd.fermion.html#qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian) - reference for the `diagonalize_fermionic_hamiltonian` function\n",
+ "\n",
+ "- [*Quantum-Centric Algorithm for Sample-Based Krylov Diagonalization*](https://arxiv.org/abs/2501.09702) - the paper this tutorial is based on"
]
}
],
diff --git a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/10af4663-7375-4b50-bae6-9f3d5106457b-0.avif b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/10af4663-7375-4b50-bae6-9f3d5106457b-0.avif
index 3c4959140ed..afcba9db6f3 100644
Binary files a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/10af4663-7375-4b50-bae6-9f3d5106457b-0.avif and b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/10af4663-7375-4b50-bae6-9f3d5106457b-0.avif differ
diff --git a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/827976ec-4815-4707-80b1-e13fb2fef309-0.avif b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/827976ec-4815-4707-80b1-e13fb2fef309-0.avif
index cf00e2e02c9..7c87b1f9297 100644
Binary files a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/827976ec-4815-4707-80b1-e13fb2fef309-0.avif and b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/827976ec-4815-4707-80b1-e13fb2fef309-0.avif differ
diff --git a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/933037d8-847e-4986-80da-5ac8d677b2ff-1.avif b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/933037d8-847e-4986-80da-5ac8d677b2ff-1.avif
new file mode 100644
index 00000000000..a820433d35a
Binary files /dev/null and b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/933037d8-847e-4986-80da-5ac8d677b2ff-1.avif differ
diff --git a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/9f2cc4d4-ecac-457a-bcae-558319668e1f-0.avif b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/9f2cc4d4-ecac-457a-bcae-558319668e1f-0.avif
index a9fee5dfafe..1329f9fc959 100644
Binary files a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/9f2cc4d4-ecac-457a-bcae-558319668e1f-0.avif and b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/9f2cc4d4-ecac-457a-bcae-558319668e1f-0.avif differ
diff --git a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/b6879566-8bf5-4c28-bfb6-b2686692e3d3-1.avif b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/b6879566-8bf5-4c28-bfb6-b2686692e3d3-1.avif
index bfaeae70f1e..6bddcbbe069 100644
Binary files a/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/b6879566-8bf5-4c28-bfb6-b2686692e3d3-1.avif and b/public/docs/images/tutorials/sample-based-krylov-quantum-diagonalization/extracted-outputs/b6879566-8bf5-4c28-bfb6-b2686692e3d3-1.avif differ