From 18155c52071044170b580a1659ce75f16751f443 Mon Sep 17 00:00:00 2001 From: Henry Zou Date: Tue, 26 May 2026 14:51:27 -0400 Subject: [PATCH 01/21] Update multi-product-formula tutorial to conform to new template - Restructure both the small-scale simulator example and the large-scale hardware example so each section follows the four-step template (Step 2 = transpile, Step 3 = execute, Step 4 = post-process). The previous labeling had Step 2 doing execution and Step 3 doing post-processing. - Rewrite the Background section to address review feedback: focus on the trade-off between Trotter step count k and circuit depth (rather than PF order), introduce r and k_j on first appearance, give the explicit eta_n / chi exponent pattern for symmetric vs non-symmetric PFs, and replace the stability paragraph with a derivation-based explanation of why t/k_min <~ 1 matters. - Fix Prerequisites links (point to the compilation-methods tutorial and SuzukiTrotter / LieTrotter API pages instead of the mismatched course URLs) and tighten the Requirements list. - Restore the per-code-cell narrative that had been trimmed from earlier passes (LSE inspection, identity_factory / Neel MPS setup, dynamic- coefficients loop). - Correct the small-scale post-plot commentary so it no longer reads as if MPFs work better at t/k > 1, and expand the sampling-error explanation with the explicit sigma_MPF^2 = sum x_j^2 sigma_{k_j}^2 formula. - Correct the large-scale section: drop the misleading "Steps 1-4 combined" header (the cell is only Step 1), fix the inline comment on the k=6 baseline (it is a depth-comparable single-circuit run, not one that matches the MPF's effective Trotter error), and rewrite the results discussion to match the new run (dynamic MPF beats every individual product formula here; exact-static MPF is worst because ||x||_1 = 5.63 amplifies hardware noise). - Suppress TeNPy's unit_cell_width future-API UserWarning in the Setup cell. The default is correct for Chain lattices, which is what CouplingMap.from_line(...) produces. - Extend cspell:ignore with the new technical / LaTeX terms. --- docs/tutorials/multi-product-formula.ipynb | 1977 +++++------------ .../extracted-outputs/25ce07a6-1.avif | Bin 49570 -> 0 bytes .../extracted-outputs/2da9c948-0.avif | Bin 11848 -> 0 bytes .../extracted-outputs/34bf68ac-0.avif | Bin 8505 -> 0 bytes .../extracted-outputs/35042576-0.avif | Bin 0 -> 9201 bytes .../extracted-outputs/64360d85-0.avif | Bin 0 -> 7716 bytes .../extracted-outputs/87d2ac0c-0.avif | Bin 6432 -> 0 bytes .../extracted-outputs/92dc20a7-0.avif | Bin 14531 -> 0 bytes .../extracted-outputs/a3eefe73-0.avif | Bin 8158 -> 0 bytes .../extracted-outputs/c5d8e90b-0.avif | Bin 82332 -> 0 bytes .../extracted-outputs/c7ee61e7-0.avif | Bin 0 -> 22448 bytes .../extracted-outputs/d751af7c-0.avif | Bin 8990 -> 0 bytes 12 files changed, 547 insertions(+), 1430 deletions(-) delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/25ce07a6-1.avif delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/2da9c948-0.avif delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/34bf68ac-0.avif create mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/35042576-0.avif create mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/64360d85-0.avif delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/87d2ac0c-0.avif delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/92dc20a7-0.avif delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/a3eefe73-0.avif delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/c5d8e90b-0.avif create mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/c7ee61e7-0.avif delete mode 100644 public/docs/images/tutorials/multi-product-formula/extracted-outputs/d751af7c-0.avif diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index d2628acee87..f24419e01ba 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -2,153 +2,262 @@ "cells": [ { "cell_type": "markdown", - "id": "9857bace", + "id": "454a9dfd", "metadata": {}, "source": [ "---\n", "title: Multi-product formulas to reduce Trotter error\n", - "description: Multi-product formulas can be used in observable estimation to reduce Trotter error or to implement time-evolution with fixed Trotter error in lower depth.\n", + "description: Use multi-product formulas in observable estimation to reduce Trotter error or implement time-evolution with fixed Trotter error in lower depth.\n", "---\n", "\n", + "{/* cspell:ignore ncol circo Layerwise markersize unbiasedness infty ndash lesssim propto tenpy unfused N\u00e9el correlator Neel exponentiating gtrsim */}\n", "\n", - "{/* cspell:ignore ncol circo Layerwise */}\n", - "{/* cspell:ignore markersize */}\n", - "\n", - "# Multi-product formulas to reduce Trotter error" + "# Multi-product formulas to reduce Trotter error\n", + "*Usage estimate: Four minutes on a Heron r2 processor (NOTE: This is an estimate only. Your runtime may vary.)*" ] }, { "cell_type": "markdown", - "id": "d08a5e51", + "id": "c4d0b2f2", + "metadata": {}, + "source": [ + "## Learning outcomes\n", + "After completing this tutorial, you can expect to understand the following information:\n", + "- How multi-product formulas (MPFs) reduce Trotter error in Hamiltonian simulation by combining expectation values from multiple shallow circuits\n", + "- When MPFs are beneficial over standard product formulas and when they are not the right tool\n", + "- How to compute static and dynamic MPF coefficients using the `qiskit_addon_mpf` package\n", + "- How to execute an MPF workflow end-to-end on IBM Quantum hardware, including transpilation, error mitigation, and post-processing" + ] + }, + { + "cell_type": "markdown", + "id": "f5dfd316", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "We suggest that users are familiar with the following topics before going through this tutorial:\n", + "- [Compilation methods for Hamiltonian simulation circuits](/docs/tutorials/compilation-methods-for-hamiltonian-simulation-circuits) — introduces Trotter (product formula) circuits in Qiskit.\n", + "- Product formulas in Qiskit, in particular the [`SuzukiTrotter`](/docs/api/qiskit/qiskit.synthesis.SuzukiTrotter) and [`LieTrotter`](/docs/api/qiskit/qiskit.synthesis.LieTrotter) synthesis classes.\n", + "- [Qiskit primitives and the Estimator interface](/docs/guides/primitives)." + ] + }, + { + "cell_type": "markdown", + "id": "07273b26", "metadata": {}, "source": [ - "*Estimated QPU usage:Four minutes on a Heron r2 processor (NOTE: This is an estimate only. Your runtime might vary.)*\n", - "\n", "## Background\n", - "This tutorial demonstrates how to use a Multi-Product Formula (MPF) to achieve a lower Trotter error on our observable compared to the one incurred by the deepest Trotter circuit that we will actually execute.\n", - "MPFs reduce the Trotter error of Hamiltonian dynamics through a weighted combination of several circuit executions. Consider the task of finding observable expectation values for the quantum state\n", - "$\\rho(t)=e^{-i H t} \\rho(0) e^{i H t}$ with the Hamiltonian $H$. One can use Product Formulas (PFs) to approximate the time-evolution $e^{-i H t}$ by doing the following:\n", "\n", - "- Write the Hamiltonian $H$ as $H=\\sum_{a=1}^d F_a,$ where $F_a$ are Hermitian operators such that each corresponding unitary can be efficiently implemented on a quantum device.\n", - "- Approximate the terms $F_a$ that do not commute with each other.\n", + "### What are multi-product formulas?\n", + "\n", + "When simulating quantum systems on a quantum computer, a central task is to approximate the time-evolution operator $e^{-iHt}$ for a Hamiltonian $H$. The standard approach uses *product formulas* (PFs), also known as Trotter-Suzuki decompositions. These decompose $H = \\sum_{a=1}^d F_a$ into terms whose individual unitaries $e^{-iF_a t}$ are efficient to implement, and then approximate the full evolution as an ordered product of these simpler unitaries.\n", + "\n", + "The first-order product formula (Lie-Trotter) is:\n", "\n", - "Then, the first-order PF (Lie-Trotter formula) is:\n", + "$$\n", + "S_1(t) := \\prod_{a=1}^d e^{-i F_a t},\n", + "$$\n", + "\n", + "which incurs a quadratic error: $S_1(t) = e^{-iHt} + \\mathcal{O}(t^2)$. Higher-order symmetric formulas $S_{2\\chi}(t)$, where $\\chi$ labels the order of the symmetric product formula (see Ref. [\\[1\\]](#references)), converge faster as $e^{-iHt} + \\mathcal{O}(t^{2\\chi+1})$, but at the cost of deeper circuits per step.\n", + "\n", + "To reduce the error at a *fixed* order $\\chi$, one usually splits the total evolution time $t$ into $k$ smaller Trotter steps. Each step approximates $e^{-iHt/k}$ by a product formula and the steps are concatenated:\n", "\n", - "$$S_1(t):=\\prod_{a=1}^d e^{-i F_a t},$$\n", + "$$\n", + "e^{-iHt} \\approx \\left[S_{2\\chi}(t/k)\\right]^k.\n", + "$$\n", "\n", - "which has a quadratic error term $S_1(t)=e^{-i H t}+\\mathcal{O}\\left(t^{2}\\right)$. One can also use higher-order PFs (Lie-Trotter-Suzuki formulas), which converge faster, and are defined recursively as:\n", + "For a $2\\chi$-order symmetric formula the residual Trotter error then scales as $\\mathcal{O}\\!\\left(t^{2\\chi+1} / k^{2\\chi}\\right)$. So increasing $k$ rapidly suppresses the Trotter error — but it also linearly deepens the circuit, and on noisy hardware that means more accumulated gate noise. This tension between **Trotter error (favors larger $k$)** and **hardware noise (favors smaller $k$)** is precisely what multi-product formulas are designed to resolve. Note that MPFs are about combining results from *different choices of $k$* at a fixed order $\\chi$ — they do not change the order of the underlying product formula.\n", "\n", - "$$S_2(t):=\\prod_{a=1}^d e^{-i F_a t/2}\\prod_{a=1}^d e^{-i F_a t/2}$$\n", + "**Multi-product formulas (MPFs)** [\\[1\\]](#references) construct a *weighted linear combination* of expectation values obtained from several shallower Trotter circuits, each using a different number of Trotter steps $k_1, k_2, \\ldots, k_r$ (a set of $r$ step counts):\n", "\n", - "$$S_{2 \\chi}(t):= S_{2 \\chi -2}(s_{\\chi}t)^2 S_{2 \\chi -2}((1-4s_{\\chi})t)S_{2 \\chi -2}(s_{\\chi}t)^2,$$\n", + "$$\n", + "\\langle A \\rangle_{\\text{MPF}}(t) = \\sum_{j=1}^r x_j \\, \\langle A \\rangle_{k_j}(t),\n", + "$$\n", "\n", - "where $\\chi$ is the order of the symmetric PF and $s_p = \\left( 4 - 4^{1/(2p-1)} \\right)^{-1}$. For long time-evolutions, one can split the time interval $t$ into $k$ intervals, called Trotter steps, of duration $t/k$ and approximate the time-evolution in each interval with a $\\chi$ order product formula $S_{\\chi}$. Thus, the PF of order $\\chi$ for time-evolution operator over $k$ Trotter steps is:\n", + "where $\\langle A \\rangle_{k_j}(t)$ is the expectation value of an observable $A$ at time $t$ estimated from a Trotter circuit with $k_j$ steps, and the coefficients $\\{x_j\\}_{j=1}^r$ are chosen so that the leading Trotter-error terms in the combination cancel. We will revisit this expression in [Step 4](#step-4-post-process-and-return-result-in-desired-classical-format), where we evaluate it explicitly to combine our Trotter results. The key practical point is that the deepest circuit in the MPF only needs $k_{\\max}$ steps, which is much smaller than the single $k$ that would be required to reach the same effective Trotter error directly. The shallower circuits make the MPF approach better suited to noisy hardware.\n", "\n", - "$$ S_{\\chi}^{k}(t) = \\left[ S_{\\chi} \\left( \\frac{t}{k} \\right)\\right]^k = e^{-i H t}+O\\left(t \\left( \\frac{t}{k} \\right)^{\\chi} \\right)$$\n", + "### How are the coefficients determined?\n", "\n", - "where the error term decreases with the number of Trotter steps $k$ and the order $\\chi$ of the PF.\n", + "There are two families of MPF coefficients:\n", "\n", - "Given an integer $k \\geq 1$ and a product formula $S_{\\chi}(t)$, the approximate time-evolved state $\\rho_k(t)$ can be obtained from $\\rho_0$ by applying $k$ iterations of the product formula $S_{\\chi}\\left(\\frac{t}{k}\\right)$.\n", + "**Static coefficients** are independent of the Hamiltonian, the initial state, and the evolution time. They are found by solving a linear system $Ax = b$ that enforces cancellation of the leading Trotter error terms. For a set of Trotter steps $\\{k_j\\}_{j=1}^r$ used with a $2\\chi$-order symmetric product formula, expanding the Trotter error in inverse powers of $k_j$ leads to constraint equations of the form:\n", "\n", "$$\n", - "\\rho_k(t)=S_{\\chi}\\left(\\frac{t}{k}\\right)^k \\rho_0 S_{\\chi}\\left(\\frac{t}{k}\\right)^{-k}\n", + "\\sum_{j=1}^r x_j = 1, \\quad \\sum_{j=1}^r \\frac{x_j}{k_j^{\\eta_n}} = 0 \\quad (n = 0, \\ldots, r-2),\n", "$$\n", "\n", - "$\\rho_k(t)$ is an approximation for $\\rho(t)$ with the Trotter approximation error ||$\\rho_k(t)-\\rho(t) ||$. If we consider a linear combination of Trotter approximations of $\\rho(t)$:\n", + "where the integer exponents $\\{\\eta_n\\}$ are the orders of the successive Trotter-error terms for the chosen product formula. For a *symmetric* $2\\chi$-order PF, the leading error in $\\left[S_{2\\chi}(t/k)\\right]^k$ scales as $1/k^{2\\chi}$, with subsequent corrections at $1/k^{2\\chi+2}, 1/k^{2\\chi+4}, \\ldots$ — so the exponents are $\\eta_n = 2\\chi + 2n$. For non-symmetric PFs, both odd and even powers contribute and $\\eta_n = 2\\chi + n$. See Ref. [\\[1\\]](#references) for the full derivation. The first equation in the system above ensures unbiasedness (the MPF reproduces the exact expectation value in the $k_j \\to \\infty$ limit), and the remaining $r-1$ equations successively cancel the first $r-1$ Trotter-error terms. When the resulting $L_1$-norm $\\|x\\|_1$ is too large (which amplifies sampling noise), one can instead solve an approximate optimization that caps $\\|x\\|_1$ while minimizing $\\|Ax - b\\|$.\n", "\n", + "**Dynamic coefficients** [\\[2\\]](#references), [\\[3\\]](#references) additionally depend on the Hamiltonian, initial state, and evolution time $t$. They minimize the Frobenius-norm distance between the true time-evolved state and the MPF approximation:\n", "\n", "$$\n", - "\\mu(t) = \\sum_{j}^{l} x_j \\rho^{k_j}_{j}\\left(\\frac{t}{k_j}\\right) + \\text{some remaining Trotter error} \\, ,\n", + "\\|\\rho(t) - \\mu^D(t)\\|_F^2 = 1 + \\sum_{i,j} M_{ij}(t)\\, x_i(t)\\, x_j(t) - 2\\sum_i L_i(t)\\, x_i(t),\n", "$$\n", "\n", - "where $x_j$ are our weighting coefficients, $\\rho^{k_j}_j$ is the density matrix corresponding to the pure state obtained by evolving the initial state with the product formula, $S^{k_j}_{\\chi}$, involving $k_j$ Trotter steps, and $j \\in {1, ..., l}$ indexes the number of PFs that make up the MPF. All the terms in $\\mu(t)$ use the same product formula $S_{\\chi}(t)$ as its base.\n", - "The goal is to improve upon ||$\\rho_k(t)-\\rho(t) \\|$ by finding $\\mu(t)$ with even lower $\\|\\mu(t)-\\rho(t)\\|$.\n", + "where $M_{ij}(t) = \\mathrm{Tr}[\\rho_{k_i}(t)\\,\\rho_{k_j}(t)]$ is the Gram matrix of overlaps between Trotter-evolved states for different step counts $k_i, k_j$, and $L_i(t) = \\mathrm{Tr}[\\rho(t)\\,\\rho_{k_i}(t)]$ measures overlap with the (approximate) exact state. In this tutorial these quantities are computed efficiently using tensor-network methods, specifically the TeNPy-based backends in `qiskit_addon_mpf`.\n", "\n", - "* $\\mu(t)$ needs not be a physical state as $x_i$ need not be positive. The goal here is to minimize the error in the expectation value of the observables and not to find a physical replacement for $\\rho(t)$.\n", - "* $k_j$ determines both the circuit depth and level of Trotter approximation. Smaller values of $k_j$ lead to shorter circuits, which incur fewer circuit errors but will be a less accurate approximation to the desired state.\n", + "### When to use MPFs\n", "\n", + "MPFs are most beneficial when:\n", "\n", - "The key here is that the remaining Trotter error given by $\\mu(t)$ is smaller than the Trotter error that one would obtain by simply using the largest $k_j$ value.\n", + "- **Circuit depth is the bottleneck.** If hardware noise limits the depth you can run, MPFs let you achieve higher effective Trotter accuracy from shallower circuits.\n", + "- **You need accurate expectation values, not full state preparation.** MPFs operate at the level of expectation values — they combine classical numbers, not quantum states. This makes them ideal for observable estimation via the Estimator primitive.\n", + "- **You combine a modest number of Trotter-step counts.** Typically combining $r = 3$–$5$ different step counts $k_j$ is sufficient to cancel several leading Trotter-error terms while keeping $\\|x\\|_1$ manageable.\n", "\n", - "You can view the usefulness of this from two perspectives:\n", + "### When MPFs may not help\n", "\n", - "1. For a fixed budget of Trotter steps that you can execute, you can obtain results with a Trotter error that is smaller in total.\n", - "2. Given some target number of Trotter steps that is too large to execute, you can use the MPF to find a collection of lower-depth circuits to run that results in a similar Trotter error." + "- **Very short evolution times.** When $t$ is small enough that a single low-order Trotter formula is already accurate, the overhead of running multiple circuits is unnecessary.\n", + "- **State-preparation tasks.** MPFs produce a corrected *expectation value*, not a corrected quantum state. If you need the actual time-evolved state (e.g., as input to another quantum subroutine), MPFs do not apply.\n", + "- **Trotter-step counts that violate the convergence regime.** The static-coefficient derivation expands each individual $\\left[S_{2\\chi}(t/k_j)\\right]^{k_j}$ as a series in $t/k_j$; this expansion only converges well when $t/k_{\\min} \\lesssim 1$. If $k_{\\min}$ is chosen too small for the given $t$, the shallowest circuit is far outside the perturbative regime, the higher-order error terms that the MPF leaves uncanceled become large, and the cancellation can require large coefficients. The $L_1$-norm $\\|x\\|_1$ is the practical diagnostic: when $\\|x\\|_1 \\gg 1$, the sampling overhead $\\propto \\|x\\|_1^2$ may outweigh the Trotter-error reduction. See the [guide on choosing Trotter steps](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) for details.\n", + "\n", + "### What this tutorial covers\n", + "\n", + "This tutorial walks through an end-to-end MPF workflow in two stages. First, a **small-scale simulator example** (10-qubit Heisenberg chain) demonstrates how to set up the problem, compute static and dynamic MPF coefficients, and compare the resulting expectation values against exact diagonalization. Then, a **large-scale hardware example** (50-qubit XXZ chain) shows how to transpile, execute on IBM Quantum hardware with error mitigation, and post-process results using the MPF coefficients. Throughout, we use the `qiskit_addon_mpf` package alongside standard Qiskit tools." ] }, { "cell_type": "markdown", - "id": "152c479f", + "id": "b5d478ce", "metadata": {}, "source": [ "## Requirements\n", "\n", "Before starting this tutorial, ensure that you have the following installed:\n", "\n", - "* 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", - "* MPF Qiskit addons (`pip install qiskit_addon_mpf`)\n", - "* Qiskit addons utils (`pip install qiskit_addon_utils`)\n", - "* Quimb library (`pip install quimb`)\n", - "* Qiskit Quimb library (`pip install qiskit-quimb`)\n", - "* Numpy v0.21 for compatibility across packages (`pip install numpy==0.21`)" - ] - }, - { - "cell_type": "markdown", - "id": "32f44dc0", - "metadata": {}, - "source": [ - "## Part I. Small-scale example" + "- Qiskit SDK v2.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n", + "- Qiskit Runtime v0.22 or later (`pip install qiskit-ibm-runtime`)\n", + "- Qiskit Aer simulator (`pip install qiskit-aer`)\n", + "- MPF Qiskit addon with the TeNPy backend (`pip install \"qiskit-addon-mpf[tenpy]\"`)\n", + "- Qiskit addon utilities (`pip install qiskit-addon-utils`)\n", + "- SciPy (`pip install scipy`)" ] }, { "cell_type": "markdown", - "id": "717dc6b6", + "id": "2584c37e", "metadata": {}, "source": [ - "### Explore the stability of MPF\n", + "## Setup\n", "\n", - "There is no obvious restriction on the choice of number of Trotter steps $k_j$ that make up the MPF state $\\mu(t)$. However, these must be picked carefully to avoid instabilities in the resulting expectation values calculated from $\\mu(t)$. A good general rule is to set the smallest Trotter step $k_{\\text{min}}$ so that $t/k_{\\text{min}} \\lt 1$. If you want to learn more about this and how to choose your other $k_j$ values, refer to the [How to choose the Trotter steps for an MPF](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) guide.\n", - "\n", - "In the example below we explore the stability of the MPF solution by calculating the expectation value of the magnetization for a range of times using different time-evolved states. Specifically, we compare the expectation values calculated from each of the approximate time-evolutions implemented with the corresponding Trotter steps and the various MPF models (static and dynamic coefficients) with the exact values of the time-evolved observable. First, let's define the parameters for the Trotter formulas and the evolution times" + "Below we collect *all* the package imports used throughout this tutorial in a single cell. We also define a `CollectAndCollapse` transpiler pass that fuses adjacent `rxx` and `ryy` rotations into a single `XXPlusYYGate`. This pass is applied both during circuit construction in Step 1 (to keep the gate count low) and indirectly when we extract the layered structure for the dynamic MPF in Step 4 (TeNPy expects two-qubit gates, not pairs of unfused rotations)." ] }, { "cell_type": "code", "execution_count": 1, - "id": "bcf32912", + "id": "bf79f9e7", "metadata": {}, "outputs": [], "source": [ + "import warnings\n", + "\n", "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from functools import partial\n", + "from copy import deepcopy\n", "\n", - "mpf_trotter_steps = [1, 2, 4]\n", - "order = 2\n", - "symmetric = False\n", + "from qiskit import QuantumCircuit\n", + "from qiskit.quantum_info import Pauli, SparsePauliOp, Statevector\n", + "from qiskit.synthesis import SuzukiTrotter\n", + "from qiskit.transpiler import CouplingMap, PassManager, Target\n", + "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", + "from qiskit.circuit.library import XXPlusYYGate\n", + "from qiskit.transpiler.passes.optimization.collect_and_collapse import (\n", + " CollectAndCollapse,\n", + " collect_using_filter_function,\n", + " collapse_to_operation,\n", + ")\n", "\n", - "trotter_times = np.arange(0.5, 1.55, 0.1)\n", - "exact_evolution_times = np.arange(trotter_times[0], 1.55, 0.05)" + "from qiskit_aer import AerSimulator\n", + "from qiskit_ibm_runtime import EstimatorV2 as Estimator, QiskitRuntimeService\n", + "\n", + "from qiskit_addon_utils.problem_generators import (\n", + " generate_xyz_hamiltonian,\n", + " generate_time_evolution_circuit,\n", + ")\n", + "from qiskit_addon_utils.slicing import slice_by_depth\n", + "from qiskit_addon_mpf.static import setup_static_lse\n", + "from qiskit_addon_mpf.dynamic import setup_dynamic_lse\n", + "from qiskit_addon_mpf.costs import (\n", + " setup_exact_problem,\n", + " setup_sum_of_squares_problem,\n", + " setup_frobenius_problem,\n", + ")\n", + "from qiskit_addon_mpf.backends.tenpy_layers import (\n", + " LayerModel,\n", + " LayerwiseEvolver,\n", + ")\n", + "from qiskit_addon_mpf.backends.tenpy_tebd import MPOState, MPS_neel_state\n", + "\n", + "from scipy.linalg import expm\n", + "\n", + "# Suppress TeNPy's `unit_cell_width` future-API warning. The default\n", + "# (`unit_cell_width=len(sites)`) is correct for Chain lattices, which is what\n", + "# `CouplingMap.from_line(...)` produces here, so the warning is informational.\n", + "warnings.filterwarnings(\n", + " \"ignore\",\n", + " message=r\".*unit_cell_width.*\",\n", + " category=UserWarning,\n", + ")\n", + "\n", + "\n", + "# --- Helper: collect XX + YY rotations into a single gate ---\n", + "def filter_function(node):\n", + " return node.op.name in {\"rxx\", \"ryy\"}\n", + "\n", + "\n", + "collect_function = partial(\n", + " collect_using_filter_function,\n", + " filter_function=filter_function,\n", + " split_blocks=True,\n", + " min_block_size=1,\n", + ")\n", + "\n", + "\n", + "def collapse_to_xx_plus_yy(block):\n", + " param = 0.0\n", + " for node in block.data:\n", + " param += node.operation.params[0]\n", + " return XXPlusYYGate(param)\n", + "\n", + "\n", + "collapse_function = partial(\n", + " collapse_to_operation,\n", + " collapse_function=collapse_to_xx_plus_yy,\n", + ")\n", + "\n", + "pm = PassManager()\n", + "pm.append(CollectAndCollapse(collect_function, collapse_function))" + ] + }, + { + "cell_type": "markdown", + "id": "24f08467", + "metadata": {}, + "source": [ + "## Small-scale simulator example" ] }, { "cell_type": "markdown", - "id": "095fa6cb", + "id": "378e82ba", "metadata": {}, "source": [ - "For this example we will use the Neel state as the initial state $\\vert \\text{Neel} \\rangle = \\vert 0101...01 \\rangle$ and the Heisenberg model on a line of 10 sites for the Hamiltonian governing the time-evolution\n", + "### Step 1: Map classical inputs to a quantum problem\n", + "\n", + "We begin with a 10-qubit Heisenberg model on a line, using the N\u00e9el state $\\vert 0101\\ldots01 \\rangle$ as the initial state. The Hamiltonian is:\n", "\n", "$$\n", - "\\hat{\\mathcal{H}}_{Heis} = J \\sum_{i=1}^{L-1} \\left(X_i X_{(i+1)}+Y_i Y_{(i+1)}+ Z_i Z_{(i+1)} \\right) \\, ,\n", + "\\hat{\\mathcal{H}}_{\\text{Heis}} = J \\sum_{i=1}^{L-1} \\left(X_i X_{i+1} + Y_i Y_{i+1} + Z_i Z_{i+1}\\right),\n", "$$\n", "\n", - "where $J$ is the coupling strength for nearest-neighbor edges." + "where $J$ is the nearest-neighbor coupling strength. We measure the ZZ correlator $Z_{L/2-1} Z_{L/2}$ on a pair of qubits in the middle of the chain, and use Trotter steps $k_j = [1, 2, 4]$ with a second-order product formula." ] }, { "cell_type": "code", "execution_count": 2, - "id": "3a20e08d", + "id": "bdd0d4fc", "metadata": {}, "outputs": [ { @@ -163,41 +272,23 @@ } ], "source": [ - "from qiskit.transpiler import CouplingMap\n", - "from rustworkx.visualization import graphviz_draw\n", - "from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian\n", - "import numpy as np\n", - "\n", - "\n", "L = 10\n", "\n", - "# Generate some coupling map to use for this example\n", + "# Generate coupling map and Hamiltonian\n", "coupling_map = CouplingMap.from_line(L, bidirectional=False)\n", - "graphviz_draw(coupling_map.graph, method=\"circo\")\n", "\n", - "# Get a qubit operator describing the Heisenberg field model\n", "hamiltonian = generate_xyz_hamiltonian(\n", " coupling_map,\n", " coupling_constants=(1.0, 1.0, 1.0),\n", " ext_magnetic_field=(0.0, 0.0, 0.0),\n", ")\n", - "\n", - "\n", "print(hamiltonian)" ] }, - { - "cell_type": "markdown", - "id": "69438c8c", - "metadata": {}, - "source": [ - "The observable that we will be measuring is magnetization on a pair of qubits in the middle of the chain." - ] - }, { "cell_type": "code", - "execution_count": null, - "id": "41fc0bd1", + "execution_count": 3, + "id": "fd3dc9c8", "metadata": {}, "outputs": [ { @@ -210,89 +301,46 @@ } ], "source": [ - "from qiskit.quantum_info import SparsePauliOp\n", - "\n", + "# Observable: ZZ on the middle pair of qubits\n", "observable = SparsePauliOp.from_sparse_list(\n", " [(\"ZZ\", (L // 2 - 1, L // 2), 1.0)], num_qubits=L\n", ")\n", "print(observable)" ] }, - { - "cell_type": "markdown", - "id": "13c67498", - "metadata": {}, - "source": [ - "We define a transpiler pass to collect the XX and YY rotations in the circuit as a single XX+YY gate. This will allow us to leverage TeNPy's spin conservation properties during the MPO computation, significantly speeding up the calculation." - ] - }, { "cell_type": "code", "execution_count": 4, - "id": "b0eec735", + "id": "398c33b2", "metadata": {}, "outputs": [], "source": [ - "from qiskit.circuit.library import XXPlusYYGate\n", - "from qiskit.transpiler import PassManager\n", - "from qiskit.transpiler.passes.optimization.collect_and_collapse import (\n", - " CollectAndCollapse,\n", - " collect_using_filter_function,\n", - " collapse_to_operation,\n", - ")\n", - "from functools import partial\n", - "\n", - "\n", - "def filter_function(node):\n", - " return node.op.name in {\"rxx\", \"ryy\"}\n", - "\n", - "\n", - "collect_function = partial(\n", - " collect_using_filter_function,\n", - " filter_function=filter_function,\n", - " split_blocks=True,\n", - " min_block_size=1,\n", - ")\n", - "\n", - "\n", - "def collapse_to_xx_plus_yy(block):\n", - " param = 0.0\n", - " for node in block.data:\n", - " param += node.operation.params[0]\n", - " return XXPlusYYGate(param)\n", - "\n", - "\n", - "collapse_function = partial(\n", - " collapse_to_operation,\n", - " collapse_function=collapse_to_xx_plus_yy,\n", - ")\n", + "# MPF parameters\n", + "mpf_trotter_steps = [1, 2, 4]\n", + "order = 2\n", + "symmetric = False\n", "\n", - "pm = PassManager()\n", - "pm.append(CollectAndCollapse(collect_function, collapse_function))" + "trotter_times = np.arange(0.5, 1.55, 0.1)\n", + "exact_evolution_times = np.arange(trotter_times[0], 1.55, 0.05)" ] }, { "cell_type": "markdown", - "id": "46470a22", + "id": "1512ba0e", "metadata": {}, "source": [ - "Then we create the circuits implementing the approximate Trotter time-evolutions." + "#### Build Trotter circuits\n", + "\n", + "We create the circuits implementing the approximate Trotter time-evolutions for each time point and each Trotter step count. The `CollectAndCollapse` pass defined in Setup collects XX and YY rotations into single XX+YY gates, enabling more efficient tensor-network simulation later." ] }, { "cell_type": "code", "execution_count": 5, - "id": "8d7b9367", + "id": "1c194d2b", "metadata": {}, "outputs": [], "source": [ - "from qiskit.synthesis import SuzukiTrotter\n", - "from qiskit_addon_utils.problem_generators import (\n", - " generate_time_evolution_circuit,\n", - ")\n", - "from qiskit import QuantumCircuit\n", - "\n", - "\n", "# Initial Neel state preparation\n", "initial_state_circ = QuantumCircuit(L)\n", "initial_state_circ.x([i for i in range(L) if i % 2 != 0])\n", @@ -322,13 +370,13 @@ { "cell_type": "code", "execution_count": 6, - "id": "92dc20a7", + "id": "c7ee61e7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "execution_count": 6, @@ -342,66 +390,83 @@ }, { "cell_type": "markdown", - "id": "aa95b6c8", + "id": "4cd6c782", "metadata": {}, "source": [ - "Next, we calculate the time-evolved expectation values from the Trotter circuits." + "### Step 2: Optimize problem for quantum hardware execution\n", + "\n", + "For the small-scale example we target the Aer simulator. Two transformations happen before the circuits are ready to execute:\n", + "\n", + "1. **Gate collection at the Hamiltonian-simulation level.** In the Setup cell we built a `CollectAndCollapse` pass that fuses adjacent `rxx` and `ryy` rotations into a single `XXPlusYYGate`. We already applied this pass when we built the Trotter circuits in Step 1 (the `pm.run(...)` call). This both reduces the two-qubit gate count and produces a structure that is more amenable to tensor-network simulation for the dynamic-coefficient computation later.\n", + "\n", + "2. **Lowering to the simulator's ISA.** Below we run Qiskit's preset pass manager at `optimization_level=3` to lower each Trotter circuit to the simulator's instruction-set architecture (ISA)." ] }, { "cell_type": "code", - "execution_count": 24, - "id": "69f60701", + "execution_count": 7, + "id": "03590a05", "metadata": {}, "outputs": [], "source": [ - "from copy import deepcopy\n", - "from qiskit_aer import AerSimulator\n", - "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n", - "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", + "aer_sim = AerSimulator()\n", + "pm_sim = generate_preset_pass_manager(backend=aer_sim, optimization_level=3)\n", "\n", + "isa_circs_all_times = [\n", + " pm_sim.run([deepcopy(c) for c in mpf_circuits])\n", + " for mpf_circuits in all_circs\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "ab6588d3", + "metadata": {}, + "source": [ + "### Step 3: Execute using Qiskit primitives\n", "\n", - "aer_sim = AerSimulator()\n", + "For the small-scale example we run the ISA-lowered Trotter circuits through the `EstimatorV2` primitive backed by Aer. Doing so gives us a *noiseless* reference value for each $(k_j, t)$ pair — these are the $\\langle A \\rangle_{k_j}(t)$ values that the MPF will combine in Step 4. We sweep over evolution times so that we can later plot the full time-series curve of each individual product formula and of the MPF." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7225d782", + "metadata": {}, + "outputs": [], + "source": [ "estimator = Estimator(mode=aer_sim)\n", "\n", "mpf_expvals_all_times, mpf_stds_all_times = [], []\n", - "for t, mpf_circuits in zip(trotter_times, all_circs):\n", - " mpf_expvals = []\n", - " circuits = [deepcopy(circuit) for circuit in mpf_circuits]\n", - " pm_sim = generate_preset_pass_manager(\n", - " backend=aer_sim, optimization_level=3\n", - " )\n", - " isa_circuits = pm_sim.run(circuits)\n", + "for isa_circuits in isa_circs_all_times:\n", " result = estimator.run(\n", " [(circuit, observable) for circuit in isa_circuits], precision=0.005\n", " ).result()\n", - " mpf_expvals = [res.data.evs for res in result]\n", - " mpf_stds = [res.data.stds for res in result]\n", - " mpf_expvals_all_times.append(mpf_expvals)\n", - " mpf_stds_all_times.append(mpf_stds)" + " mpf_expvals_all_times.append([res.data.evs for res in result])\n", + " mpf_stds_all_times.append([res.data.stds for res in result])" ] }, { "cell_type": "markdown", - "id": "b84e4000", + "id": "a384f017", "metadata": {}, "source": [ - "We also calculate the exact expectation values for comparison." + "### Step 4: Post-process and return result in desired classical format\n", + "\n", + "Step 4 is where the MPF is actually constructed. Even though the coefficients $x_j$ are *computed* here (and, for the dynamic variant, this computation can be intensive), conceptually they are a classical recipe for combining the quantum measurements from Step 3 into a single corrected expectation value — so we treat the whole coefficient + combination workflow as post-processing.\n", + "\n", + "To assess how well the MPF tracks the true dynamics, we first compute the exact time-evolved expectation values by directly exponentiating the Hamiltonian. This is only tractable because $L = 10$; in the large-scale hardware example below we will have to rely on tensor-network estimates instead." ] }, { "cell_type": "code", - "execution_count": null, - "id": "32ecef77", + "execution_count": 9, + "id": "a223a360", "metadata": {}, "outputs": [], "source": [ - "from scipy.linalg import expm\n", - "from qiskit.quantum_info import Statevector\n", - "\n", "exact_expvals = []\n", "for t in exact_evolution_times:\n", - " # Exact expectation values\n", " exp_H = expm(-1j * t * hamiltonian.to_matrix())\n", " initial_state = Statevector(initial_state_circ).data\n", " time_evolved_state = exp_H @ initial_state\n", @@ -416,132 +481,67 @@ }, { "cell_type": "markdown", - "id": "949130d1", + "id": "361e726e", "metadata": {}, "source": [ "#### Static MPF coefficients\n", "\n", - "Static MPFs are those where the $x_j$ values do not depend on the evolution time, $t$. Let's consider the order $\\chi = 1$ PF with $k_j$ Trotter steps, this can be written as:\n", - "\n", - "$$ S_1^{k_j}\\left( \\frac{t}{k_j} \\right)=e^{-i H t}+ \\sum_{n=1}^{\\infty} A_n \\frac{t^{n+1}}{k_j^n} $$\n", - "\n", - "where $A_n$ are matrices which depend on the commutators of $F_a$ terms in the decomposition of the Hamiltonian. It is important to note that $A_n$ themselves are independent of time and the number of Trotter steps $k_j$. Therefore, it is possible to cancel out lower-order error terms contributing to $\\mu(t)$ with a careful choice of the weights $x_j$ of the linear combination. To cancel the Trotter error for the first $l-1$ terms (these will give the largest contributions as they correspond to the lower number of Trotter steps) in the expression for $\\mu(t)$, the coefficients $x_j$ must satisfy the following equations:\n", - "\n", - "$$ \\sum_{j=1}^l x_j = 1 $$\n", - "$$ \\sum_{j=1}^{l-1} \\frac{x_j}{k_j^{n}} = 0 $$\n", - "\n", - "with $n=0, ... l-2$. The first equation guarantees that there is no bias in the constructed state $\\mu(t)$, while the second equation ensures the cancellation of the Trotter errors. For higher-order PF, the second equation becomes $ \\sum_{j=1}^{l-1} \\frac{x_j}{k_j^{\\eta}} = 0 $ where $\\eta = \\chi + 2n$ for symmetric PFs and $\\eta = \\chi + n$ otherwise, with $n=0, ..., l-2$. The resulting error (Refs. [\\[1\\]](#references),[\\[2\\]](#references)) is then\n", - "\n", - "$$ \\epsilon = \\mathcal{O} \\left( \\frac{t^{l+1}}{k_1^l} \\right).$$\n", - "\n", - "\n", - "Determining the static MPF coefficients for a given set of $k_j$ values amounts to solving the linear system of equations defined by the two equations above for the variables $x_j$: $Ax=b$. Where $x$ are our coefficients of interest, $A$ is a matrix which depends on $k_j$ and the type of PF we use ($S$), and $b$ is a vector of constraints. Specifically:\n", - "\n", - "$$A_{0,j} = 1 $$\n", - "$$A_{i>0,j} = k_{j}^{-(\\chi + s(i-1))}$$\n", - "$$b_0 = 1$$\n", - "$$b_{i>0} = 0 $$\n", - "\n", + "Static MPFs use coefficients $x_j$ that are independent of the evolution time, the Hamiltonian, and the initial state. We set up the linear system $Ax = b$ described in the Background and solve for the coefficients. The matrix $A$ is determined by the Trotter step counts $k_j$, the order $\\chi$ of the product formula, and whether the formula is symmetric (which controls the exponents $\\eta_n$).\n", "\n", - "where $\\chi$ is the ``order``, $s$ is $2$ if ``symmetric`` is ``True`` and $1$ otherwise, $k_{j}$ are the ``trotter_steps``, and $x$ are the variables to solve for. The indices $i$ and $j$ start at $0$. We can also visualize this in matrix form:\n", + "For our small-scale example we use $k_j = [1, 2, 4]$ with a non-symmetric order-$2\\chi=2$ Suzuki-Trotter formula (so $\\chi=1$ and $\\eta_n = 2 + n$, giving $\\eta_0 = 2,\\, \\eta_1 = 3$). The system becomes:\n", "\n", "$$\n", "A =\n", "\\begin{bmatrix}\n", - "A_{0,0} & A_{0,1} & A_{0,2} & ... \\\\\n", - "A_{1,0} & A_{1,1} & A_{1,2} & ... \\\\\n", - "A_{2,0} & A_{2,1} & A_{2,2} & ... \\\\\n", - "... & ... & ... & ...\n", - "\\end{bmatrix} =\n", - "\\begin{bmatrix}\n", - "1 & 1 & 1 & ... \\\\\n", - "k_{0}^{-(\\chi + s(1-1))} & k_{1}^{-(\\chi + s(1-1))} & k_{2}^{-(\\chi + s(1-1))} & ... \\\\\n", - "k_{0}^{-(\\chi + s(2-1))} & k_{1}^{-(\\chi + s(2-1))} & k_{2}^{-(\\chi + s(2-1))} & ... \\\\\n", - "... & ... & ... & ...\n", - "\\end{bmatrix}\n", - "$$\n", - "\n", - "and\n", - "\n", - "$$\n", + "1 & 1 & 1\\\\\n", + "1 & \\frac{1}{2^2} & \\frac{1}{4^2} \\\\\n", + "1 & \\frac{1}{2^3} & \\frac{1}{4^3} \\\\\n", + "\\end{bmatrix}, \\quad\n", "b =\n", "\\begin{bmatrix}\n", - "b_{0} \\\\\n", - "b_{1} \\\\\n", - "b_{2} \\\\\n", - "...\n", - "\\end{bmatrix} =\n", - "\\begin{bmatrix}\n", "1 \\\\\n", "0 \\\\\n", - "0 \\\\\n", - "...\n", - "\\end{bmatrix}\n", + "0\n", + "\\end{bmatrix}.\n", "$$\n", "\n", - "\n", - "\n", - "For more details, refer to the documentation of the Linear System of Equations ([LSE](https://qiskit.github.io/qiskit-addon-mpf/stubs/qiskit_addon_mpf.static.LSE.html)).\n", - "\n", - "We can find a solution for $x$ analytically as $x = A^{-1}b$; see for example Refs. [\\[1\\]](#references) or [\\[2\\]](#references).\n", - "However, this exact solution can be \"ill-conditioned\", resulting in very large L1-norms of our coefficients, $x$, which can lead to bad performance of the MPF.\n", - "Instead, one can also obtain an approximate solution that minimizes the L1-norm of $x$ in order to attempt to optimize the MPF behavior." + "The first row enforces unbiasedness ($\\sum_j x_j = 1$); the second and third rows cancel the leading $1/k^2$ and next-order $1/k^3$ Trotter-error terms respectively." ] }, { "cell_type": "markdown", - "id": "f16ac209", + "id": "4f2ca1e2", "metadata": {}, "source": [ "##### Set up the LSE\n", "\n", - "Now that we have chosen our $k_j$ values, we must first construct the LSE, $Ax=b$ as explained above.\n", - "The matrix $A$ depends not only on $k_j$ but also our choice of PF, in particular its _order_.\n", - "Additionally, you might take into account whether the PF is symmetric or not (see [\\[1\\]](#references)) by setting `symmetric=True/False`.\n", - "However, this is not required, as shown by Ref. [\\[2\\]](#references)." + "We use `setup_static_lse` from `qiskit_addon_mpf.static` to assemble the matrix $A$ and right-hand-side vector $b$ described above. The matrix $A$ depends not only on $k_j$ but also on our choice of product formula — in particular its *order* $\\chi$ and whether it is *symmetric*. The `symmetric` flag controls the exponent pattern $\\eta_n$ (symmetric formulas only produce even-power Trotter-error terms; see Ref. [\\[1\\]](#references)). Note that, as shown in Ref. [\\[2\\]](#references), setting `symmetric=True` is not strictly necessary even when the underlying PF is symmetric — the non-symmetric LSE remains valid (it just enforces extra unneeded constraints).\n", + "\n", + "For our example we already set `order = 2` and `symmetric = False` in Step 1." ] }, { "cell_type": "code", - "execution_count": 9, - "id": "509bee67", + "execution_count": 10, + "id": "827b0b42", "metadata": {}, "outputs": [], "source": [ - "from qiskit_addon_mpf.static import setup_static_lse\n", - "\n", "lse = setup_static_lse(mpf_trotter_steps, order=order, symmetric=symmetric)" ] }, { "cell_type": "markdown", - "id": "d6f76196", + "id": "003e4bdd", "metadata": {}, "source": [ - "Let's work through the values chosen above to construct the $A$ matrix and the $b$ vector. With $j=0,1, 2$ Trotter steps $k_j = [1, 2, 4]$, order $\\chi = 2$ and choice of non-symmetric Trotter steps ($s=1$), we have that the matrix elements of $A$ below the first row are determined by the expression $A_{i>0,j} = k_{j}^{-(2 + 1(i-1))}$, specifically:\n", - "\n", - "$$ A_{0,0} = A_{0,1} = A_{0,2} = 1 $$\n", - "$$ A_{1,j} = k_{j}^{-1} \\rightarrow A_{1,0} = \\frac{1}{1^2}, \\;, A_{1,1} = \\frac{1}{2^2}, \\;, A_{1,2} = \\frac{1}{4^2}$$\n", - "$$ A_{2,j} = k_{j}^{-2} \\rightarrow A_{2,0} = \\frac{1}{1^3}, \\;, A_{2,1} = \\frac{1}{2^3}, \\;, A_{2,2} = \\frac{1}{4^3}$$\n", - "\n", - "or in matrix form:\n", - "\n", - "$$\n", - "A =\n", - "\\begin{bmatrix}\n", - "1 & 1 & 1\\\\\n", - "1 & \\frac{1}{2^2} & \\frac{1}{4^2} \\\\\n", - "1 & \\frac{1}{2^3} & \\frac{1}{4^3} \\\\\n", - "\\end{bmatrix}\n", - "$$\n", - "\n", - "This is possible to see by inspecting the `lse` object:" + "Inspect the constructed matrix $A$ and vector $b$ to confirm they match the system written above." ] }, { "cell_type": "code", - "execution_count": 10, - "id": "4982ce27", + "execution_count": 11, + "id": "6f879978", "metadata": {}, "outputs": [ { @@ -552,7 +552,7 @@ " [1. , 0.125 , 0.015625]])" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -562,62 +562,38 @@ ] }, { - "cell_type": "markdown", - "id": "c6f54a8f", + "cell_type": "code", + "execution_count": 12, + "id": "64fe7db9", "metadata": {}, - "source": [ - "While the vector of constraints $b$ has the following elements:\n", - "$$ b_{0} = 1 $$\n", - "$$ b_1 = b_2 = 0 $$\n", - "\n", - "Thus,\n", - "\n", - "$$\n", - "b =\n", - "\\begin{bmatrix}\n", - "1 \\\\\n", - "0 \\\\\n", - "0\n", - "\\end{bmatrix}\n", - "$$\n", - "\n", - "\n", - "And similarly in `lse`:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "c5b4f202", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1., 0., 0.])" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [ + { + "data": { + "text/plain": [ + "array([1., 0., 0.])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "lse.b" ] }, { "cell_type": "markdown", - "id": "fc47c29f", + "id": "16ab9f79", "metadata": {}, "source": [ - "The `lse` object has methods for finding the static coefficients $x_j$ satisfying the system of equations." + "With the LSE in hand, we solve for the static coefficients $x_j$ via `lse.solve()` (this is the direct $x = A^{-1}b$ solution)." ] }, { "cell_type": "code", - "execution_count": 12, - "id": "4459394c", + "execution_count": 13, + "id": "7b69192a", "metadata": {}, "outputs": [ { @@ -637,20 +613,18 @@ }, { "cell_type": "markdown", - "id": "6b228e6f", + "id": "1c238a59", "metadata": {}, "source": [ "##### Optimize for $x$ using an exact model\n", "\n", - "Alternatively to computing $x=A^{-1}b$, you can also use [setup_exact_model](https://qiskit.github.io/qiskit-addon-mpf/stubs/qiskit_addon_mpf.static.setup_exact_model.html) to construct a [cvxpy.Problem](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem) instance that uses the LSE as constraints and whose optimal solution will yield $x$.\n", - "\n", - "In the next section, it will be clear why this interface exists." + "Alternatively to computing $x = A^{-1}b$, you can use [setup\\_exact\\_model](https://qiskit.github.io/qiskit-addon-mpf/stubs/qiskit_addon_mpf.static.setup_exact_model.html) to construct a [cvxpy.Problem](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem) instance that uses the LSE as constraints and whose optimal solution will yield $x$." ] }, { "cell_type": "code", - "execution_count": 13, - "id": "238ad3fe", + "execution_count": 14, + "id": "993465e9", "metadata": {}, "outputs": [ { @@ -662,25 +636,15 @@ } ], "source": [ - "from qiskit_addon_mpf.costs import setup_exact_problem\n", - "\n", "model_exact, coeffs_exact = setup_exact_problem(lse)\n", "model_exact.solve()\n", "print(coeffs_exact.value)" ] }, - { - "cell_type": "markdown", - "id": "31799d19", - "metadata": {}, - "source": [ - "As an indicator whether an MPF constructed with these coefficients will yield good results, we can use the L1-norm (see also Ref. [\\[1\\]](#references))." - ] - }, { "cell_type": "code", - "execution_count": 14, - "id": "ee706bcd", + "execution_count": 15, + "id": "eb61ea70", "metadata": {}, "outputs": [ { @@ -695,26 +659,23 @@ "print(\n", " \"L1 norm of the exact coefficients:\",\n", " np.linalg.norm(coeffs_exact.value, ord=1),\n", - ") # ord specifies the norm. ord=1 is for L1" + ")" ] }, { "cell_type": "markdown", - "id": "577dc339", + "id": "dac0472b", "metadata": {}, "source": [ "##### Optimize for $x$ using an approximate model\n", "\n", - "It might happen that the L1 norm for the chosen set of $k_j$ values is deemed too high.\n", - "If that is the case and you cannot choose a different set of $k_j$ values, you can use an approximate solution to the LSE instead of an exact one.\n", - "\n", - "To do so, simply use [setup_approximate_model](https://qiskit.github.io/qiskit-addon-mpf/stubs/qiskit_addon_mpf.static.setup_approximate_model.html) to construct a different [cvxpy.Problem](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem) instance, which constrains the L1-norm to a chosen threshold while minimizing the difference of $Ax$ and $b$." + "It might happen that the $L_1$ norm for the chosen set of $k_j$ values is deemed too high. If that is the case and you cannot choose a different set of $k_j$ values, you can use an approximate solution that constrains the $L_1$-norm to a chosen threshold while minimizing $\\|Ax - b\\|$. Check out the guide on [How to use the approximate model](https://qiskit.github.io/qiskit-addon-mpf/how_tos/using_approximate_model.html)." ] }, { "cell_type": "code", "execution_count": 16, - "id": "3e06be50", + "id": "0cd7dea4", "metadata": {}, "outputs": [ { @@ -727,8 +688,6 @@ } ], "source": [ - "from qiskit_addon_mpf.costs import setup_sum_of_squares_problem\n", - "\n", "model_approx, coeffs_approx = setup_sum_of_squares_problem(\n", " lse, max_l1_norm=1.5\n", ")\n", @@ -742,76 +701,29 @@ }, { "cell_type": "markdown", - "id": "214239bb", - "metadata": {}, - "source": [ - "Note that you have complete freedom over how to solve this optimization problem, which means that you can change the optimization solver, its convergence thresholds, and so on.\n", - "Check out the respective guide on [How to use the approximate model](https://qiskit.github.io/qiskit-addon-mpf/how_tos/using_approximate_model.html)." - ] - }, - { - "cell_type": "markdown", - "id": "a3fca123", + "id": "10fd05eb", "metadata": {}, "source": [ "#### Dynamic MPF coefficients\n", "\n", - "In the previous section, we introduced a static MPF that improves on the standard Trotter approximation. However, this static version does not necessarily minimize the approximation error. Concretely, the static MPF, denoted $\\mu^S(t)$, is not the optimal projection of $\\rho(t)$ onto the subspace spanned by the product-formula states $\\{\\rho_{k_i}(t)\\}_{i=1}^r$.\n", - "\n", - "To address this, we consider a dynamic MPF (introduced in Ref. [\\[2\\]](#references) and experimentally demonstrated in Ref. [\\[3\\]](#references)) that does minimize the approximation error in the Frobenius norm. Formally, we focus on minimizing\n", - "\n", - "$$\n", - "\\|\\rho(t) - \\mu^D(t)\\|_F^2 \\;=\\; \\mathrm{Tr}\\bigl[ \\left( \\rho(t) - \\mu^D(t)\\right)^2 \\bigr],\n", - "$$\n", - "\n", - "with respect to some coefficients $x_i(t)$ at each time $t$. The *optimal* projector in the Frobenius norm is then $\\mu^D(t) \\;=\\; \\sum_{i=1}^r x_i(t)\\,\\rho_{k_i}(t)$, and we call $\\mu^D(t)$ the *dynamic* MPF. Plugging in the definitions above:\n", - "\n", - "\n", - "\n", - "$$\n", - "\\|\\rho(t) - \\mu^D(t)\\|_F^2\n", - "\\;=\\; \\\\\n", - "= \\mathrm{Tr}\\bigl[ \\left( \\rho(t) - \\mu^D(t)\\right)^2 \\bigr]\n", - "\\;=\\; \\\\\n", - "= \\mathrm{Tr}\\bigl[ \\left( \\rho(t) - \\sum_{i=1}^r x_i(t)\\,\\rho_{k_i}(t) \\right) \\left( \\rho(t) - \\sum_{j=1}^r x_j(t)\\,\\rho_{k_j}(t) \\right) \\bigr]\n", - "\\;=\\; \\\\\n", - "= 1 \\;+\\; \\sum_{i,j=1}^r M_{i,j}(t)\\,x_i(t)\\,x_j(t)\n", - "\\;-\\;\n", - "2 \\sum_{i=1}^r L_i^{\\mathrm{exact}}(t)\\,x_i(t),\n", - "$$\n", - "\n", - "where $M_{i,j}(t)$ is the *Gram matrix*, defined by\n", - "\n", - "$$\n", - "M_{i,j}(t) \\;=\\; \\mathrm{Tr}\\bigl[\\rho_{k_i}(t)\\,\\rho_{k_j}(t)\\bigr]\n", - "\\;=\\;\n", - "\\bigl|\\langle \\psi_{\\mathrm{in}} \\!\\mid S\\bigl(t/k_i\\bigr)^{-k_i}\\,S\\bigl(t/k_j\\bigr)^{k_j} \\!\\mid \\psi_{\\mathrm{in}} \\rangle \\bigr|^2.\n", - "$$\n", - "\n", - "\n", - "and\n", + "The static MPF cancels Trotter-error terms in a Hamiltonian- and state-agnostic way, so it does not necessarily produce the smallest possible approximation error for a given Hamiltonian and initial state. The dynamic MPF (Refs. [\\[2\\]](#references), [\\[3\\]](#references)) instead finds time-dependent coefficients $x_i(t)$ that minimize the Frobenius-norm distance $\\|\\rho(t) - \\mu^D(t)\\|_F^2$ at each time $t$. As shown in the Background, this requires the overlap matrix $M_{ij}(t)$ between Trotter-evolved states and the overlap $L_i(t)$ with the exact state — both of which we estimate using tensor-network (TeNPy) backends in `qiskit_addon_mpf`.\n", "\n", - "$$\n", - "L_i^{\\mathrm{exact}}(t) = \\mathrm{Tr}[\\rho(t)\\,\\rho_{k_i}(t)]\n", - "$$\n", + "To set up the dynamic LSE we need three ingredients:\n", "\n", - "represents the overlap between the exact state $\\rho(t)$ and each product-formula approximation $\\rho_{k_i}(t)$. In practical scenarios, these overlaps may only be measured approximately due to noise or partial access to $\\rho(t)$.\n", + "1. An **approximate evolver factory** that the addon will run for each $k_j$ to produce $\\rho_{k_j}(t)$ as an MPS/MPO. We build it from the layered structure of the order-$2$ Trotter circuit (one layer per `slice_by_depth`), wrapped as a `LayerwiseEvolver` with TeNPy truncation parameters.\n", + "2. An **exact evolver factory** that produces a high-accuracy reference $\\rho(t)$. We use a small-time-step fourth-order Suzuki-Trotter circuit (`dt=0.1`, `order=4`) as a proxy for exact evolution.\n", + "3. An **identity factory** and an **initial-state MPS** that seed the TeNPy simulation.\n", "\n", - "Here, $\\lvert\\psi_{\\mathrm{in}}\\rangle$ is the initial state, and $S(\\cdot)$ is the operation applied in the product formula. By choosing the coefficients $x_i(t)$ that minimize this expression (and handling approximate overlap data when $\\rho(t)$ is not fully known), we obtain the “best” (in a Frobenius-norm sense) dynamic approximation of $\\rho(t)$ within the MPF subspace. The quantities $L_i(t)$ and $M_{i,j}(t)$ can be calculated efficiently using tensor network methods [\\[3\\]](#references). The MPF Qiskit addon provides several \"backends\" to carry out the calculation. The example below shows the most flexible way to do so, and the [TeNPy layer-based backend](https://qiskit.github.io/qiskit-addon-mpf/apidocs/qiskit_addon_mpf.backends.tenpy_layers.html#module-qiskit_addon_mpf.backends.tenpy_layers) docs also explain in great detail. To use this method, start from the circuit implementing the desired time-evolution and create models that represent these operations from the layers of the corresponding circuit. Finally, an `Evolver` object is created that can be used to generate the time-evolved quantities $M_{i,j}(t)$ and $L_i(t)$. We start by creating the `Evolver` object corresponding to the approximate time-evolution ([`ApproxEvolverFactory`](https://qiskit.github.io/qiskit-addon-mpf/apidocs/qiskit_addon_mpf.dynamic.html#qiskit_addon_mpf.dynamic.ApproxEvolverFactory)) implemented by the circuits. In particular, pay extra attention to the `order` variable so that they match. Note that in generating the circuits corresponding to the approximate time-evolution, we use placeholder values for the `time = 1.0` and the number of Trotter steps (`reps=1`). The correct approximating circuits are then produced by the dynamic problem solver in `setup_dynamic_lse`." + "The cell below constructs the approximate evolver factory." ] }, { "cell_type": "code", "execution_count": 17, - "id": "87323ed2", + "id": "52d78403", "metadata": {}, "outputs": [], "source": [ - "from qiskit_addon_utils.slicing import slice_by_depth\n", - "from qiskit_addon_mpf.backends.tenpy_layers import LayerModel\n", - "from qiskit_addon_mpf.backends.tenpy_layers import LayerwiseEvolver\n", - "from functools import partial\n", - "\n", "# Create approximate time-evolution circuits\n", "single_2nd_order_circ = generate_time_evolution_circuit(\n", " hamiltonian, time=1.0, synthesis=SuzukiTrotter(reps=1, order=order)\n", @@ -844,26 +756,26 @@ }, { "cell_type": "markdown", - "id": "fd39f15a", + "id": "91d2783e", "metadata": {}, "source": [ "\n", - "The options of `LayerwiseEvolver` that determine the details of the tensor network simulation must be chosen carefully to avoid setting up an ill-defined optimization problem.\n", + " The options of `LayerwiseEvolver` that determine the details of the tensor network simulation must be chosen carefully to avoid setting up an ill-defined optimization problem.\n", "" ] }, { "cell_type": "markdown", - "id": "d6b611e3", + "id": "1c702f67", "metadata": {}, "source": [ - "We then set up the exact evolver (for example, [`ExactEvolverFactory`](https://qiskit.github.io/qiskit-addon-mpf/apidocs/qiskit_addon_mpf.dynamic.html#qiskit_addon_mpf.dynamic.ExactEvolverFactory)), which returns an [`Evolver`](https://qiskit.github.io/qiskit-addon-mpf/apidocs/qiskit_addon_mpf.backends.html#qiskit_addon_mpf.backends.Evolver) object computing the true or “reference” time-evolution. Realistically, we would approximate the exact evolution by using a higher-order Suzuki–Trotter formula or another reliable method with a small time step. Below, we approximate the exact time-evolved state with a fourth-order Suzuki-Trotter formula using a small time step `dt=0.1`, which means the number of Trotter steps used at time $t$ is $k=t/dt$. We also specify some TeNPy-specific truncation options to bound the maximum bond dimension of the underlying tensor network, as well as the minimum singular values of the split tensor network bonds. These parameters can affect the accuracy of the expectation value calculated with the dynamic MPF coefficients, so it is important to explore a range of values to find the optimal balance between computational time and accuracy. Note that the calculation of the MPF coefficients does not rely of the expectation value of the PF obtained from hardware execution, and therefore it can be tuned in post-processing." + "We approximate the exact time-evolved state with a fourth-order Suzuki-Trotter formula using a small time step `dt=0.1`. The TeNPy truncation parameters can affect accuracy, so it is important to explore a range of values." ] }, { "cell_type": "code", - "execution_count": 20, - "id": "10ca6c85", + "execution_count": 18, + "id": "abab8bfc", "metadata": {}, "outputs": [], "source": [ @@ -894,23 +806,19 @@ }, { "cell_type": "markdown", - "id": "1eb4d98c", + "id": "2486594c", "metadata": {}, "source": [ - "Next, create your system’s initial state in a format compatible with TeNPy (for example, an `MPS_neel_state`=$\\vert 0101...01 \\rangle$). This sets up the many-body wavefunction you’ll evolve in time $\\lvert\\psi_{\\mathrm{in}}\\rangle$ as a tensor." + "Finally, we define an `identity_factory` that yields the initial MPO state and prepare the N\u00e9el initial state as an MPS that matches the lattice used by the layered Trotter model." ] }, { "cell_type": "code", - "execution_count": null, - "id": "69758099", + "execution_count": 19, + "id": "1e216575", "metadata": {}, "outputs": [], "source": [ - "from qiskit_addon_mpf.backends.tenpy_tebd import MPOState\n", - "from qiskit_addon_mpf.backends.tenpy_tebd import MPS_neel_state\n", - "\n", - "\n", "def identity_factory():\n", " return MPOState.initialize_from_lattice(models[0].lat, conserve=True)\n", "\n", @@ -920,16 +828,16 @@ }, { "cell_type": "markdown", - "id": "057d479e", + "id": "5658315c", "metadata": {}, "source": [ - "For each time step $t$ we set up the dynamic linear system of equations with the [`setup_dynamic_lse`](https://qiskit.github.io/qiskit-addon-mpf/apidocs/qiskit_addon_mpf.dynamic.html) method. The corresponding object contains the information about the dynamic MPF problem: `lse.A` gives the Gram matrix $M$ while `lse.b` gives the overlap $L$. We can then solve the LSE (when not ill-defined) to find the dynamic coefficients using the `setup_frobenius_problem`. It is important to note the difference with the static coefficients, which only depend on the details of the product formula used and are independent of the details of the time-evolution (Hamiltonian and initial state)." + "With the factories in place we now compute the dynamic coefficients at each evolution time. For each $t$, `setup_dynamic_lse` builds the relevant overlap matrices via TeNPy, and `setup_frobenius_problem` returns a `cvxpy.Problem` that minimizes the Frobenius-norm cost. The solver returns coefficients $x_j(t)$ tailored to that time; we collect them in `mpf_dynamic_coeffs_list`. If the solver fails for a given $t$, we fall back to zero coefficients so the loop continues." ] }, { "cell_type": "code", - "execution_count": 22, - "id": "bed976ac", + "execution_count": 20, + "id": "b05dc012", "metadata": {}, "outputs": [ { @@ -962,9 +870,6 @@ } ], "source": [ - "from qiskit_addon_mpf.dynamic import setup_dynamic_lse\n", - "from qiskit_addon_mpf.costs import setup_frobenius_problem\n", - "\n", "mpf_dynamic_coeffs_list = []\n", "for t in trotter_times:\n", " print(f\"Computing dynamic coefficients for time={t}\")\n", @@ -988,22 +893,24 @@ }, { "cell_type": "markdown", - "id": "bf4a82e0", + "id": "4f8814e3", "metadata": {}, "source": [ - "Finally, plot these expectation values throughout the evolution time." + "#### Combine Trotter expectation values with the MPF coefficients\n", + "\n", + "Now we evaluate $\\langle A \\rangle_{\\text{MPF}}(t) = \\sum_j x_j \\, \\langle A \\rangle_{k_j}(t)$ for each set of coefficients (static-exact, static-approximate, and dynamic), propagate the per-circuit standard errors, and plot the resulting time series against the exact-diagonalization curve." ] }, { "cell_type": "code", - "execution_count": null, - "id": "2da9c948", + "execution_count": 21, + "id": "35042576", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "metadata": {}, @@ -1011,8 +918,6 @@ } ], "source": [ - "import matplotlib.pyplot as plt\n", - "\n", "sym = {1: \"^\", 2: \"s\", 4: \"p\"}\n", "# Get expectation values at all times for each Trotter step\n", "for k, step in enumerate(mpf_trotter_steps):\n", @@ -1032,7 +937,7 @@ " marker=sym[step],\n", " color=\"grey\",\n", " label=f\"{mpf_trotter_steps[k]} Trotter steps\",\n", - " ) # , , )\n", + " )\n", "\n", "# Get expectation values at all times for the static MPF with exact coeffs\n", "exact_mpf_curve, exact_mpf_curve_error = [], []\n", @@ -1061,7 +966,7 @@ ")\n", "\n", "\n", - "# Get expectation values at all times for the static MPF with approximate\n", + "# Get expectation values at all times for the static MPF with approximate coeffs\n", "approx_mpf_curve, approx_mpf_curve_error = [], []\n", "for trotter_expvals, trotter_stds in zip(\n", " mpf_expvals_all_times, mpf_stds_all_times\n", @@ -1083,11 +988,12 @@ " yerr=approx_mpf_curve_error,\n", " markersize=4,\n", " marker=\"o\",\n", + " label=\"Static MPF - Approx\",\n", " color=\"orange\",\n", - " label=\"Static MPF - Approximate\",\n", ")\n", "\n", - "# # Get expectation values at all times for the dynamic MPF\n", + "\n", + "# Get expectation values at all times for the dynamic MPF\n", "dynamic_mpf_curve, dynamic_mpf_curve_error = [], []\n", "for trotter_expvals, trotter_stds, dynamic_coeffs in zip(\n", " mpf_expvals_all_times, mpf_stds_all_times, mpf_dynamic_coeffs_list\n", @@ -1109,761 +1015,94 @@ " yerr=dynamic_mpf_curve_error,\n", " markersize=4,\n", " marker=\"o\",\n", - " color=\"pink\",\n", " label=\"Dynamic MPF\",\n", + " color=\"pink\",\n", ")\n", "\n", "\n", - "plt.plot(\n", - " exact_evolution_times,\n", - " exact_expvals,\n", - " lw=3,\n", - " color=\"red\",\n", - " label=\"Exact time-evolution\",\n", - ")\n", - "\n", - "\n", - "plt.title(\n", - " f\"Expectation values for (ZZ,{(L//2-1, L//2)}) as a function of time\"\n", - ")\n", - "plt.xlabel(\"Time\")\n", - "plt.ylabel(\"Expectation Value\")\n", - "plt.legend()\n", - "plt.grid()" - ] - }, - { - "cell_type": "markdown", - "id": "3a4c6912", - "metadata": {}, - "source": [ - "In the cases like the example above, where the $k=1$ PF behaves poorly at all times, the quality of the dynamic MPF results is also heavily affected. In such situations, it is useful to investigate the possibility of using individual PFs with higher number of Trotter steps to improve the overall quality of the results. In these simulations, we see the interplay of different types of errors: error from finite sampling, and Trotter error from the product formulas. MPF helps to reduce the Trotter error due to the product formulas but incur in higher sampling error compared to the product formulas. This can be advantageous, as product formulas can reduce the sampling error with increased sampling, but the systematic error due to the Trotter approximation remains untouched.\n", - "\n", - "Another interesting behavior that we can observe from the plot is that the expectation value for the PF for $k=1$ starts to behave erratically (on top of not being a good approximation for the exact one) at times for which $t/k > 1 $, as explained in the [guide](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) on how to choose the number of Trotter steps." - ] - }, - { - "cell_type": "markdown", - "id": "2a16f346", - "metadata": {}, - "source": [ - "### Step 1: Map classical inputs to a quantum problem\n", - "Let's now consider a single time $t=1.0$ and calculate the expectation value of the magnetization with the various methods using one QPU. The particular choice of $t$ was done so to maximize the difference between the various methods and observe their relative efficacy. To determine the window of time for which dynamic MPF is guaranteed to produce observables with lower error than any of the individual Trotter formulas within the multi-product, we can implement the “MPF test” - see equation (17) and surrounding text in [\\[3\\]](#references)." - ] - }, - { - "cell_type": "markdown", - "id": "623cc755", - "metadata": {}, - "source": [ - "#### Set up the Trotter circuits\n", - "\n", - "At this point, we have found our expansion coefficients, $x$, and all that is left to do is to generate the Trotterized quantum circuits.\n", - "Once again, the [qiskit_addon_utils.problem_generators](/docs/api/qiskit-addon-utils/problem-generators) module comes to the rescue with a useful function to do this:" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "3dc0dcf2", - "metadata": {}, - "outputs": [], - "source": [ - "from qiskit.synthesis import SuzukiTrotter\n", - "from qiskit_addon_utils.problem_generators import (\n", - " generate_time_evolution_circuit,\n", - ")\n", - "from qiskit import QuantumCircuit\n", - "\n", - "\n", - "total_time = 1.0\n", - "mpf_circuits = []\n", - "for k in mpf_trotter_steps:\n", - " # Initial Neel state preparation\n", - " circuit = QuantumCircuit(L)\n", - " circuit.x([i for i in range(L) if i % 2 != 0])\n", - "\n", - " trotter_circ = generate_time_evolution_circuit(\n", - " hamiltonian,\n", - " synthesis=SuzukiTrotter(order=order, reps=k),\n", - " time=total_time,\n", - " )\n", - "\n", - " circuit.compose(trotter_circ, inplace=True)\n", - "\n", - " mpf_circuits.append(pm.run(circuit))" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "87d2ac0c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mpf_circuits[-1].draw(\"mpl\", fold=-1, scale=0.4)" - ] - }, - { - "cell_type": "markdown", - "id": "97eb3019", - "metadata": {}, - "source": [ - "### Step 2: Optimize problem for quantum hardware execution\n", - "Let's return to the calculation of the expectation value for a single time point. We'll pick a backend for executing the experiment on hardware." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c9a3020e", - "metadata": {}, - "outputs": [], - "source": [ - "from qiskit_ibm_runtime import QiskitRuntimeService\n", - "\n", - "\n", - "service = QiskitRuntimeService()\n", - "backend = service.least_busy(min_num_qubits=127)\n", - "print(backend)\n", - "\n", - "qubits = list(range(backend.num_qubits))" - ] - }, - { - "cell_type": "markdown", - "id": "6eeaac1b", - "metadata": {}, - "source": [ - "Then we remove outlier qubits from the coupling map to ensure that the layout stage of the transpiler doesn't include them. Below we use the reported backend properties stored in the `target` object and remove qubits that either have measurement error or a two-qubit gate above a certain threshold (`max_meas_err`, `max_twoq_err`) or $T_2$ time (which determines the loss of coherence) below a certain threshold (`min_t2`)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8bb2c619", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "size of largest component 10\n" - ] - } - ], - "source": [ - "import copy\n", - "from qiskit.transpiler import Target, CouplingMap\n", - "\n", - "target = backend.target\n", - "instruction_2q = \"cz\"\n", - "\n", - "cmap = target.build_coupling_map(filter_idle_qubits=True)\n", - "cmap_list = list(cmap.get_edges())\n", - "\n", - "max_meas_err = 0.012\n", - "min_t2 = 40\n", - "max_twoq_err = 0.005\n", - "\n", - "# Remove qubits with bad measurement or t2\n", - "cust_cmap_list = copy.deepcopy(cmap_list)\n", - "for q in range(target.num_qubits):\n", - " meas_err = target[\"measure\"][(q,)].error\n", - " if target.qubit_properties[q].t2 is not None:\n", - " t2 = target.qubit_properties[q].t2 * 1e6\n", - " else:\n", - " t2 = 0\n", - " if meas_err > max_meas_err or t2 < min_t2:\n", - " # print(q)\n", - " for q_pair in cmap_list:\n", - " if q in q_pair:\n", - " try:\n", - " cust_cmap_list.remove(q_pair)\n", - " except ValueError:\n", - " continue\n", - "\n", - "# Remove qubits with bad 2q gate or t2\n", - "for q in cmap_list:\n", - " twoq_gate_err = target[instruction_2q][q].error\n", - " if twoq_gate_err > max_twoq_err:\n", - " # print(q)\n", - " for q_pair in cmap_list:\n", - " if q == q_pair:\n", - " try:\n", - " cust_cmap_list.remove(q_pair)\n", - " except ValueError:\n", - " continue\n", - "\n", - "\n", - "cust_cmap = CouplingMap(cust_cmap_list)\n", - "\n", - "cust_target = Target.from_configuration(\n", - " basis_gates=backend.configuration().basis_gates\n", - " + [\"measure\"], # or whatever new set of gates\n", - " coupling_map=cust_cmap,\n", - ")\n", - "\n", - "sorted_components = sorted(\n", - " [list(comp.physical_qubits) for comp in cust_cmap.connected_components()],\n", - " reverse=True,\n", - ")\n", - "print(\"size of largest component\", len(sorted_components[0]))" - ] - }, - { - "cell_type": "markdown", - "id": "2aba48dd", - "metadata": {}, - "source": [ - "We want to set `max_meas_err`, `min_t2`, and `max_twoq_err` such that we find a large enough subset of qubits that supports the circuit to run. In our case it's enough to find a 10-qubit 1D chain." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "c5d8e90b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cust_cmap.draw()" - ] - }, - { - "cell_type": "markdown", - "id": "4d11a75a", - "metadata": {}, - "source": [ - "We can then map the circuit and observable onto physical qubits of the device." - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "id": "bbbec0ec", - "metadata": {}, - "outputs": [], - "source": [ - "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", - "\n", - "transpiler = generate_preset_pass_manager(\n", - " optimization_level=3, target=cust_target\n", - ")\n", - "\n", - "transpiled_circuits = [transpiler.run(circ) for circ in mpf_circuits]\n", - "\n", - "qubits_layouts = [\n", - " [\n", - " idx\n", - " for idx, qb in circuit.layout.initial_layout.get_physical_bits().items()\n", - " if qb._register.name != \"ancilla\"\n", - " ]\n", - " for circuit in transpiled_circuits\n", - "]\n", - "\n", - "transpiled_circuits = []\n", - "for circuit, layout in zip(mpf_circuits, qubits_layouts):\n", - " transpiler = generate_preset_pass_manager(\n", - " optimization_level=3, backend=backend, initial_layout=layout\n", - " )\n", - " transpiled_circuit = transpiler.run(circuit)\n", - " transpiled_circuits.append(transpiled_circuit)\n", - "\n", - "\n", - "# transform the observable defined on virtual qubits to\n", - "# an observable defined on all physical qubits\n", - "isa_observables = [\n", - " observable.apply_layout(circ.layout) for circ in transpiled_circuits\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "id": "25ce07a6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "51\n", - "OrderedDict([('sx', 310), ('rz', 232), ('cz', 132), ('x', 19)])\n" - ] - }, - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "execution_count": 73, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print(transpiled_circuits[-1].depth(lambda x: x.operation.num_qubits == 2))\n", - "print(transpiled_circuits[-1].count_ops())\n", - "transpiled_circuits[-1].draw(\"mpl\", idle_wires=False, fold=False)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "c5edec73", - "metadata": {}, - "source": [ - "### Step 3: Execute using Qiskit primitives\n", - "With the Estimator primitive we can obtain the estimation of expectation value from the QPU. We execute the optimized AQC circuits with additional error mitigation and suppression techniques." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f91a669f", - "metadata": {}, - "outputs": [], - "source": [ - "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n", - "\n", - "\n", - "estimator = Estimator(mode=backend)\n", - "estimator.options.default_shots = 30000\n", - "\n", - "# Set simple error suppression/mitigation options\n", - "estimator.options.dynamical_decoupling.enable = True\n", - "estimator.options.twirling.enable_gates = True\n", - "estimator.options.twirling.enable_measure = True\n", - "estimator.options.twirling.num_randomizations = \"auto\"\n", - "estimator.options.twirling.strategy = \"active-accum\"\n", - "estimator.options.resilience.measure_mitigation = True\n", - "estimator.options.experimental.execution_path = \"gen3-turbo\"\n", - "\n", - "estimator.options.resilience.zne_mitigation = True\n", - "estimator.options.resilience.zne.noise_factors = (1, 3, 5)\n", - "estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n", - "\n", - "estimator.options.environment.job_tags = [\"mpf small\"]\n", - "\n", - "\n", - "job = estimator.run(\n", - " [\n", - " (circ, observable)\n", - " for circ, observable in zip(transpiled_circuits, isa_observables)\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "87484abf", - "metadata": {}, - "source": [ - "### Step 4: Post-process and return result in desired classical format\n", - "\n", - "\n", - "The only post-processing step is to combine the expectation value obtained from the Qiskit Runtime primitives at different Trotter steps using the respective MPF coefficients. For an observable $A$ we have:\n", - "\n", - "$$ \\langle A \\rangle_{\\text{mpf}} = \\text{Tr} [A \\mu(t)] = \\sum_{j} x_j \\text{Tr} [A \\rho_{k_j}] = \\sum_{j} x_j \\langle A \\rangle_j$$\n", - "\n", - "First, we extract the individual expectation values obtained for each of the Trotter circuits:" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "a5ef9913", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[array(-0.06361607), array(-0.23820448), array(-0.50271805)]\n" - ] - } - ], - "source": [ - "result_exp = job.result()\n", - "evs_exp = [res.data.evs for res in result_exp]\n", - "evs_std = [res.data.stds for res in result_exp]\n", - "\n", - "print(evs_exp)" - ] - }, - { - "cell_type": "markdown", - "id": "446ab041", - "metadata": {}, - "source": [ - "Next, we simply recombine them with our MPF coefficients to yield the total expectation values of the MPF. Below, we do so for each of the different ways by which we have computed $x$." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "3ee35ecb", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Exact static MPF expectation value: -0.6329590442738475 +- 0.012798249760406036\n", - "Approximate static MPF expectation value: -0.5690390035339492 +- 0.010459559917168473\n", - "Dynamic MPF expectation value: -0.4655579758795695 +- 0.007639139186720507\n" - ] - } - ], - "source": [ - "exact_mpf_std = np.sqrt(\n", - " sum(\n", - " [\n", - " (coeff**2) * (std**2)\n", - " for coeff, std in zip(coeffs_exact.value, evs_std)\n", - " ]\n", - " )\n", - ")\n", - "print(\n", - " \"Exact static MPF expectation value: \",\n", - " evs_exp @ coeffs_exact.value,\n", - " \"+-\",\n", - " exact_mpf_std,\n", - ")\n", - "approx_mpf_std = np.sqrt(\n", - " sum(\n", - " [\n", - " (coeff**2) * (std**2)\n", - " for coeff, std in zip(coeffs_approx.value, evs_std)\n", - " ]\n", - " )\n", - ")\n", - "print(\n", - " \"Approximate static MPF expectation value: \",\n", - " evs_exp @ coeffs_approx.value,\n", - " \"+-\",\n", - " approx_mpf_std,\n", - ")\n", - "dynamic_mpf_std = np.sqrt(\n", - " sum(\n", - " [\n", - " (coeff**2) * (std**2)\n", - " for coeff, std in zip(mpf_dynamic_coeffs_list[7], evs_std)\n", - " ]\n", - " )\n", - ")\n", - "print(\n", - " \"Dynamic MPF expectation value: \",\n", - " evs_exp @ mpf_dynamic_coeffs_list[7],\n", - " \"+-\",\n", - " dynamic_mpf_std,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "8a99f6b2", - "metadata": {}, - "source": [ - "Finally, for this small problem we can compute the exact reference value using [scipy.linalg.expm](https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.expm.html) as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "4a7dd8fc", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Exact expectation value -0.39909900734489434\n" - ] - } - ], - "source": [ - "from scipy.linalg import expm\n", - "from qiskit.quantum_info import Statevector\n", - "\n", - "exp_H = expm(-1j * total_time * hamiltonian.to_matrix())\n", - "\n", - "initial_state_circuit = QuantumCircuit(L)\n", - "initial_state_circuit.x([i for i in range(L) if i % 2 != 0])\n", - "initial_state = Statevector(initial_state_circuit).data\n", - "\n", - "time_evolved_state = exp_H @ initial_state\n", - "\n", - "exact_obs = (\n", - " time_evolved_state.conj() @ observable.to_matrix() @ time_evolved_state\n", - ")\n", - "print(\"Exact expectation value \", exact_obs.real)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "a3eefe73", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "sym = {1: \"^\", 2: \"s\", 4: \"p\"}\n", - "# Get expectation values at all times for each Trotter step\n", - "for k, step in enumerate(mpf_trotter_steps):\n", - " plt.errorbar(\n", - " k,\n", - " evs_exp[k],\n", - " yerr=evs_std[k],\n", - " alpha=0.5,\n", - " markersize=4,\n", - " marker=sym[step],\n", - " color=\"grey\",\n", - " label=f\"{mpf_trotter_steps[k]} Trotter steps\",\n", - " ) # , , )\n", - "\n", - "\n", - "plt.errorbar(\n", - " 3,\n", - " evs_exp @ coeffs_exact.value,\n", - " yerr=exact_mpf_std,\n", - " markersize=4,\n", - " marker=\"o\",\n", - " color=\"purple\",\n", - " label=\"Static MPF\",\n", - ")\n", - "\n", - "plt.errorbar(\n", - " 4,\n", - " evs_exp @ coeffs_approx.value,\n", - " yerr=approx_mpf_std,\n", - " markersize=4,\n", - " marker=\"o\",\n", - " color=\"orange\",\n", - " label=\"Approximate static MPF\",\n", - ")\n", - "\n", - "plt.errorbar(\n", - " 5,\n", - " evs_exp @ mpf_dynamic_coeffs_list[7],\n", - " yerr=dynamic_mpf_std,\n", - " markersize=4,\n", - " marker=\"o\",\n", - " color=\"pink\",\n", - " label=\"Dynamic MPF\",\n", - ")\n", - "\n", - "plt.axhline(\n", - " y=exact_obs.real,\n", - " linestyle=\"--\",\n", - " color=\"red\",\n", - " label=\"Exact time-evolution\",\n", - ")\n", - "\n", - "\n", - "plt.title(\n", - " f\"Expectation values for (ZZ,{(L//2-1, L//2)}) at time {total_time} for the different methods \"\n", - ")\n", - "plt.xlabel(\"Method\")\n", - "plt.ylabel(\"Expectation Value\")\n", - "plt.legend(loc=\"upper center\", bbox_to_anchor=(0.5, -0.2), ncol=2)\n", - "plt.grid(alpha=0.1)\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "921fb0c1", - "metadata": {}, - "source": [ - "In the example above, the dynamic MPF method performs best in terms of expectation value, improving over what we would have obtained by using the highest number of Trotter steps alone. Even though the various MPF techniques are not always achieving an improved expectation value compared to the highest number of Trotter steps (like the exact and the approximate model in the plot above), the standard deviation of these values captures well the increased variance incurred when using the MPF technique. This highlights uncertainty around the obtained expectation value, which always includes the expectation value we would expect from an exact time-evolution of the system. On the other hand, the expectation values calculated with the lower number of Trotter steps fails to capture the exact expectation value within their uncertainty, thus confidently returning the wrong result." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "7d639f4a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "relative error for each trotter steps [0.33548293650112293, 0.16089452939226306, 0.10361904247828346]\n", - "relative error with MPF exact coeffs 0.2338600369291003\n", - "relative error with MPF approx coeffs 0.16993999618905486\n", - "relative error with MPF dynamic coeffs 0.06645896853467514\n" - ] - } - ], - "source": [ - "def relative_error(ev, exact_ev):\n", - " return abs(ev - exact_ev)\n", - "\n", - "\n", - "relative_error_k = [relative_error(ev, exact_obs.real) for ev in evs_exp]\n", - "relative_error_mpf = relative_error(evs_exp @ mpf_coeffs, exact_obs.real)\n", - "relative_error_approx_mpf = relative_error(\n", - " evs_exp @ coeffs_approx.value, exact_obs.real\n", - ")\n", - "relative_error_dynamic_mpf = relative_error(\n", - " evs_exp @ mpf_dynamic_coeffs_list[7], exact_obs.real\n", + "# Exact expectation values\n", + "plt.plot(\n", + " exact_evolution_times,\n", + " exact_expvals,\n", + " color=\"red\",\n", + " linestyle=\"--\",\n", + " label=\"Exact time-evolution\",\n", ")\n", "\n", - "print(\"relative error for each trotter steps\", relative_error_k)\n", - "print(\"relative error with MPF exact coeffs\", relative_error_mpf)\n", - "print(\"relative error with MPF approx coeffs\", relative_error_approx_mpf)\n", - "print(\"relative error with MPF dynamic coeffs\", relative_error_dynamic_mpf)" + "plt.title(f\"$\\\\langle Z_{{{L//2-1}}} Z_{{{L//2}}} \\\\rangle$ vs time\")\n", + "plt.xlabel(\"Time\")\n", + "plt.ylabel(\"Expectation Value\")\n", + "plt.legend(loc=\"upper center\", bbox_to_anchor=(0.5, -0.2), ncol=2)\n", + "plt.grid(alpha=0.1)\n", + "plt.tight_layout()\n", + "plt.show()" ] }, { "cell_type": "markdown", - "id": "0130299b", + "id": "34923748", "metadata": {}, "source": [ - "## Part II: scale it up\n", + "The plot above illustrates the interplay between Trotter error and sampling error.\n", + "\n", + "- **Trotter error.** The individual product formulas (grey markers) deviate from the exact curve more and more as time grows, with the largest deviation for $k=1$ — that circuit is the shallowest, but it is also already in the regime where $t/k \\gtrsim 1$, so the leading $1/k^{2}$ error term is large. The MPF combinations (colored markers) cancel several of these leading Trotter-error terms, so they track the exact curve much more closely than any single $k_j$ circuit. The remaining gap reflects the higher-order Trotter terms that the MPF does *not* cancel: an order-$2$, $r=3$ static MPF only kills the first two error orders, and at large $t/k_{\\min}$ the uncancelled tail eventually dominates — so MPF is not a free pass to use very shallow circuits at arbitrary times.\n", "\n", - "Let's scale the problem up beyond what is possible to simulate exactly. In this section we will focus on reproducing some of the results shown in Ref. [\\[3\\]](#references)." + "- **Sampling error.** The wider error bars on the MPF curves are a direct consequence of the linear combination: propagating independent per-circuit standard errors $\\sigma_{k_j}$ gives a total variance $\\sigma_{\\text{MPF}}^2 = \\sum_j x_j^2 \\, \\sigma_{k_j}^2$. So the larger the $\\|x\\|_2$ (and in practice the $\\|x\\|_1$, which is what we control), the more shots are required to reach a given target uncertainty. This is the trade-off behind the approximate-solver option in the Background: we cap $\\|x\\|_1$ to keep this overhead manageable. Crucially, unlike Trotter error, sampling error shrinks with $1/\\sqrt{N_{\\text{shots}}}$, so it can always be reduced by spending more shots.\n", + "\n", + "In the large-scale hardware example below, hardware noise enters as an additional error source on each $\\langle A \\rangle_{k_j}$, which similarly gets amplified by the MPF coefficients. We will see how error mitigation interacts with MPFs in that section." ] }, { "cell_type": "markdown", - "id": "85a5e83a", + "id": "6fa763ff", "metadata": {}, "source": [ - "### Step 1: Map classical inputs to a quantum problem" + "## Large-scale hardware example\n", + "\n", + "Let's scale the problem up beyond what is possible to simulate exactly. In this section we reproduce some of the results shown in Ref. [\\[3\\]](#references), using a 50-qubit XXZ chain at time $t = 3$. We use the same four-step workflow as above, but pull out the hardware-specific details (qubit filtering, transpilation, and error mitigation) into their own subsections after Step 1." ] }, { "cell_type": "markdown", - "id": "951205d9", + "id": "481fea70", "metadata": {}, "source": [ - "#### Hamiltonian\n", + "### Step 1: Map classical inputs to a quantum problem\n", "\n", - "For the large-scale example, we use the XXZ model on a line of 50 sites:\n", + "The mapping mirrors the small-scale example: define a Hamiltonian, choose Trotter parameters, compute MPF coefficients (static and dynamic), and build circuits. The key differences are:\n", "\n", - "$$\n", - "\\hat{\\mathcal{H}}_{XXZ} = \\sum_{i=1}^{L-1} J_{i,(i+1)}\\left(X_i X_{(i+1)}+Y_i Y_{(i+1)}+ 2\\cdot Z_i Z_{(i+1)} \\right) \\, ,\n", - "$$\n", + "- An **XXZ Hamiltonian** on 50 sites with random couplings drawn from $\\mathcal{U}(0.5, 1.5)$ (Ref. [\\[3\\]](#references)).\n", + "- A **symmetric** second-order Trotter formula with $k_j = [2, 3, 4]$ (so $\\chi=1$, `symmetric=True`).\n", + "- A single fixed evolution time $t = 3$.\n", + "- An additional **single-circuit comparison run with $k = 6$ Trotter steps**, used as a baseline. We chose $k = 6$ because its two-qubit depth on hardware is comparable to the deepest MPF constituent ($k_{\\max}=4$) plus the overhead of running multiple MPF circuits — so $k=6$ is a fair \"single deep circuit\" comparison against the MPF combination, not a circuit that targets the MPF's effective Trotter error (which would require many more steps).\n", "\n", - "where $J_{i,(i+1)}$ is a random coefficient corresponding to edge $(i, i+1)$. This is the Hamiltonian considered in the demonstration presented in Ref. [\\[3\\]](#references)." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "34bf68ac", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "L = 50\n", - "# Generate some coupling map to use for this example\n", - "coupling_map = CouplingMap.from_line(L, bidirectional=False)\n", - "graphviz_draw(coupling_map.graph, method=\"circo\")" + "Note that even though we are still in Step 1 here (mapping + circuit construction), we also pre-compute the dynamic coefficients alongside the static ones in this cell. Dynamic coefficients depend on $H$ and $t$ but not on the quantum measurements, so they can be computed any time before Step 4. We do it now to keep all the MPF-specific setup in one place." ] }, { "cell_type": "code", - "execution_count": null, - "id": "06e49110", + "execution_count": 22, + "id": "a019ac32", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYY', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'XXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'YYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],\n", - " coeffs=[1. +0.j, 2.09762701+0.j, 2.09762701+0.j, 4.19525402+0.j,\n", - " 2.43037873+0.j, 2.43037873+0.j, 4.86075747+0.j, 2.20552675+0.j,\n", - " 2.20552675+0.j, 4.4110535 +0.j, 2.08976637+0.j, 2.08976637+0.j,\n", - " 4.17953273+0.j, 1.8473096 +0.j, 1.8473096 +0.j, 3.6946192 +0.j,\n", - " 2.29178823+0.j, 2.29178823+0.j, 4.58357645+0.j, 1.87517442+0.j,\n", - " 1.87517442+0.j, 3.75034885+0.j, 2.783546 +0.j, 2.783546 +0.j,\n", - " 5.567092 +0.j, 2.92732552+0.j, 2.92732552+0.j, 5.85465104+0.j,\n", - " 1.76688304+0.j, 1.76688304+0.j, 3.53376608+0.j, 2.58345008+0.j,\n", - " 2.58345008+0.j, 5.16690015+0.j, 2.05778984+0.j, 2.05778984+0.j,\n", - " 4.11557968+0.j, 2.13608912+0.j, 2.13608912+0.j, 4.27217824+0.j,\n", - " 2.85119328+0.j, 2.85119328+0.j, 5.70238655+0.j, 1.14207212+0.j,\n", - " 1.14207212+0.j, 2.28414423+0.j, 1.1742586 +0.j, 1.1742586 +0.j,\n", - " 2.3485172 +0.j, 1.04043679+0.j, 1.04043679+0.j, 2.08087359+0.j,\n", - " 2.66523969+0.j, 2.66523969+0.j, 5.33047938+0.j, 2.5563135 +0.j,\n", - " 2.5563135 +0.j, 5.112627 +0.j, 2.7400243 +0.j, 2.7400243 +0.j,\n", - " 5.48004859+0.j, 2.95723668+0.j, 2.95723668+0.j, 5.91447337+0.j,\n", - " 2.59831713+0.j, 2.59831713+0.j, 5.19663426+0.j, 1.92295872+0.j,\n", - " 1.92295872+0.j, 3.84591745+0.j, 2.56105835+0.j, 2.56105835+0.j,\n", - " 5.12211671+0.j, 1.23654885+0.j, 1.23654885+0.j, 2.4730977 +0.j,\n", - " 2.27984204+0.j, 2.27984204+0.j, 4.55968409+0.j, 1.28670657+0.j,\n", - " 1.28670657+0.j, 2.57341315+0.j, 2.88933783+0.j, 2.88933783+0.j,\n", - " 5.77867567+0.j, 2.04369664+0.j, 2.04369664+0.j, 4.08739329+0.j,\n", - " 1.82932388+0.j, 1.82932388+0.j, 3.65864776+0.j, 1.52911122+0.j,\n", - " 1.52911122+0.j, 3.05822245+0.j, 2.54846738+0.j, 2.54846738+0.j,\n", - " 5.09693476+0.j, 1.91230066+0.j, 1.91230066+0.j, 3.82460133+0.j,\n", - " 2.1368679 +0.j, 2.1368679 +0.j, 4.2737358 +0.j, 1.0375796 +0.j,\n", - " 1.0375796 +0.j, 2.0751592 +0.j, 2.23527099+0.j, 2.23527099+0.j,\n", - " 4.47054199+0.j, 2.22419145+0.j, 2.22419145+0.j, 4.44838289+0.j,\n", - " 2.23386799+0.j, 2.23386799+0.j, 4.46773599+0.j, 2.88749616+0.j,\n", - " 2.88749616+0.j, 5.77499231+0.j, 2.3636406 +0.j, 2.3636406 +0.j,\n", - " 4.7272812 +0.j, 1.7190158 +0.j, 1.7190158 +0.j, 3.4380316 +0.j,\n", - " 1.87406391+0.j, 1.87406391+0.j, 3.74812782+0.j, 2.39526239+0.j,\n", - " 2.39526239+0.j, 4.79052478+0.j, 1.12045094+0.j, 1.12045094+0.j,\n", - " 2.24090189+0.j, 2.33353343+0.j, 2.33353343+0.j, 4.66706686+0.j,\n", - " 2.34127574+0.j, 2.34127574+0.j, 4.68255148+0.j, 1.42076512+0.j,\n", - " 1.42076512+0.j, 2.84153024+0.j, 1.2578526 +0.j, 1.2578526 +0.j,\n", - " 2.51570519+0.j, 1.6308567 +0.j, 1.6308567 +0.j, 3.2617134 +0.j])\n" + "Static coefficients: [ 0.26666667 -2.31428571 3.04761905]\n", + "L1 norm: 5.628571428571431\n", + "Approximate coefficients: [-0.24255546 -0.25744454 1.5 ]\n", + "L1 norm (approx): 2.0\n", + "Computing dynamic coefficients for time=3\n" ] } ], "source": [ - "import numpy as np\n", - "from qiskit.quantum_info import SparsePauliOp, Pauli\n", - "\n", + "# -------------------------Step 1: Map classical inputs-------------------------\n", + "L = 50\n", + "coupling_map = CouplingMap.from_line(L, bidirectional=False)\n", "\n", - "# Generate random coefficients for our XXZ Hamiltonian\n", + "# XXZ Hamiltonian with random couplings (Ref. [3])\n", "np.random.seed(0)\n", "even_edges = list(coupling_map.get_edges())[::2]\n", "odd_edges = list(coupling_map.get_edges())[1::2]\n", @@ -1880,174 +1119,49 @@ " num_qubits=L,\n", " )\n", "\n", - "print(hamiltonian)" - ] - }, - { - "cell_type": "markdown", - "id": "5f87dc5d", - "metadata": {}, - "source": [ - "For an observable we choose $Z_{24}Z_{25}$, as seen in the lower panel Fig. 5 of Ref. [\\[3\\]](#references)." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "3bb3c684", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIII'],\n", - " coeffs=[1.+0.j])\n" - ] - } - ], - "source": [ "observable = SparsePauliOp.from_sparse_list(\n", " [(\"ZZ\", (L // 2 - 1, L // 2), 1.0)], num_qubits=L\n", ")\n", - "print(observable)" - ] - }, - { - "cell_type": "markdown", - "id": "8a0fb376", - "metadata": {}, - "source": [ - "#### Choose Trotter steps\n", - "The experiment showcased in Fig. 4 of Ref. [\\[3\\]](#references) uses $k_j = [2, 3, 4]$ symmetric Trotter steps of order $2$. We focus on the results for time $t=3$, where the MPF and a PF with a higher number of Trotter steps (6 in this case) have the same Trotter error. However, the MPF expectation value is calculated from circuits corresponding to the lower number of Trotter steps and thus shallower. In practice, even if the MPF and the deeper Trotter steps circuit have the same Trotter error, we expect the experimental expectation value calculated from the MPF circuits to be closer to the theory one, as it entails running shallower circuits less exposed to hardware noise compared to the circuit corresponding to the higher Trotter step PF." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "06e08219", - "metadata": {}, - "outputs": [], - "source": [ + "\n", "total_time = 3\n", "mpf_trotter_steps = [2, 3, 4]\n", "order = 2\n", - "symmetric = True" - ] - }, - { - "cell_type": "markdown", - "id": "85ea15da", - "metadata": {}, - "source": [ - "#### Set up the LSE\n", - "Here we look at the static MPF coefficients for this problem." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "7fee3d13", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The static coefficients associated with the ansatze are: [ 0.26666667 -2.31428571 3.04761905]\n", - "L1 norm: 5.628571428571431\n" - ] - } - ], - "source": [ + "symmetric = True\n", + "\n", + "# Static coefficients\n", "lse = setup_static_lse(mpf_trotter_steps, order=order, symmetric=symmetric)\n", "mpf_coeffs = lse.solve()\n", - "print(\n", - " f\"The static coefficients associated with the ansatze are: {mpf_coeffs}\"\n", - ")\n", - "print(\"L1 norm:\", np.linalg.norm(mpf_coeffs, ord=1))" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "7ee6bdf3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[-0.24255546 -0.25744454 1.5 ]\n", - "L1 norm of the approximate coefficients: 2.0\n" - ] - } - ], - "source": [ + "print(f\"Static coefficients: {mpf_coeffs}\")\n", + "print(f\"L1 norm: {np.linalg.norm(mpf_coeffs, ord=1)}\")\n", + "\n", "model_approx, coeffs_approx = setup_sum_of_squares_problem(\n", " lse, max_l1_norm=2.0\n", ")\n", "model_approx.solve()\n", - "print(coeffs_approx.value)\n", - "print(\n", - " \"L1 norm of the approximate coefficients:\",\n", - " np.linalg.norm(coeffs_approx.value, ord=1),\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "87262bc4", - "metadata": {}, - "source": [ - "#### Dynamic coefficients" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b2fec4a5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "# Create approximate time-evolution circuits\n", + "print(f\"Approximate coefficients: {coeffs_approx.value}\")\n", + "print(f\"L1 norm (approx): {np.linalg.norm(coeffs_approx.value, ord=1)}\")\n", + "\n", + "# -------------------------Dynamic coefficients-------------------------\n", "single_2nd_order_circ = generate_time_evolution_circuit(\n", " hamiltonian, time=1.0, synthesis=SuzukiTrotter(reps=1, order=order)\n", ")\n", - "single_2nd_order_circ = pm.run(single_2nd_order_circ) # collect XX and YY\n", + "single_2nd_order_circ = pm.run(single_2nd_order_circ)\n", "\n", - "# Find layers in the circuit\n", "layers = slice_by_depth(single_2nd_order_circ, max_slice_depth=1)\n", - "\n", - "# Create tensor network models\n", "models = [\n", " LayerModel.from_quantum_circuit(layer, conserve=\"Sz\") for layer in layers\n", "]\n", "\n", - "# Create the time-evolution object\n", "approx_factory = partial(\n", " LayerwiseEvolver,\n", " layers=models,\n", " options={\n", " \"preserve_norm\": False,\n", - " \"trunc_params\": {\n", - " \"chi_max\": 64,\n", - " \"svd_min\": 1e-8,\n", - " \"trunc_cut\": None,\n", - " },\n", + " \"trunc_params\": {\"chi_max\": 64, \"svd_min\": 1e-8, \"trunc_cut\": None},\n", " \"max_delta_t\": 4,\n", " },\n", ")\n", "\n", - "# Create exact time-evolution circuits\n", "single_4th_order_circ = generate_time_evolution_circuit(\n", " hamiltonian, time=1.0, synthesis=SuzukiTrotter(reps=1, order=4)\n", ")\n", @@ -2057,18 +1171,13 @@ " for layer in slice_by_depth(single_4th_order_circ, max_slice_depth=1)\n", "]\n", "\n", - "# Create the time-evolution object\n", "exact_factory = partial(\n", " LayerwiseEvolver,\n", " layers=exact_model_layers,\n", " dt=0.1,\n", " options={\n", " \"preserve_norm\": False,\n", - " \"trunc_params\": {\n", - " \"chi_max\": 64,\n", - " \"svd_min\": 1e-8,\n", - " \"trunc_cut\": None,\n", - " },\n", + " \"trunc_params\": {\"chi_max\": 64, \"svd_min\": 1e-8, \"trunc_cut\": None},\n", " \"max_delta_t\": 3,\n", " },\n", ")\n", @@ -2080,8 +1189,8 @@ "\n", "mps_initial_state = MPS_neel_state(models[0].lat)\n", "\n", - "\n", - "lse = setup_dynamic_lse(\n", + "print(f\"Computing dynamic coefficients for time={total_time}\")\n", + "lse_dyn = setup_dynamic_lse(\n", " mpf_trotter_steps,\n", " total_time,\n", " identity_factory,\n", @@ -2089,113 +1198,75 @@ " approx_factory,\n", " mps_initial_state,\n", ")\n", - "problem, coeffs = setup_frobenius_problem(lse)\n", + "problem, coeffs_dyn = setup_frobenius_problem(lse_dyn)\n", "try:\n", " problem.solve()\n", - " mpf_dynamic_coeffs = coeffs.value\n", + " mpf_dynamic_coeffs = coeffs_dyn.value\n", "except Exception as error:\n", - " print(error, \"Calculation Failed for time\", total_time)\n", - "print(\"\")" - ] - }, - { - "cell_type": "markdown", - "id": "43829572", - "metadata": {}, - "source": [ - "#### Construct each of the Trotter circuits in our MPF decomposition" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "b79c5547", - "metadata": {}, - "outputs": [], - "source": [ - "from qiskit.synthesis import SuzukiTrotter\n", - "from qiskit_addon_utils.problem_generators import (\n", - " generate_time_evolution_circuit,\n", - ")\n", - "from qiskit import QuantumCircuit\n", - "\n", + " mpf_dynamic_coeffs = np.zeros(len(mpf_trotter_steps))\n", + " print(error, \"Calculation Failed\")\n", "\n", + "# -------------------------Step 1 (cont): Build circuits-------------------------\n", "mpf_circuits = []\n", "for k in mpf_trotter_steps:\n", - " # Initial state preparation |1010..>\n", " circuit = QuantumCircuit(L)\n", " circuit.x([i for i in range(L) if i % 2])\n", - "\n", " trotter_circ = generate_time_evolution_circuit(\n", " hamiltonian,\n", " synthesis=SuzukiTrotter(reps=k, order=order),\n", " time=total_time,\n", " )\n", - "\n", " circuit.compose(trotter_circ, qubits=range(L), inplace=True)\n", + " mpf_circuits.append(circuit)\n", "\n", - " mpf_circuits.append(circuit)" - ] - }, - { - "cell_type": "markdown", - "id": "ffd915d7", - "metadata": {}, - "source": [ - "#### Construct Trotter circuit with comparable Trotter error to MPF" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "b22143ff", - "metadata": {}, - "outputs": [], - "source": [ - "k = 6\n", - "\n", - "# Initial state preparation |1010..>\n", + "# Baseline \"single deep circuit\" comparison run with k=6 Trotter steps.\n", + "# (Its two-qubit depth is comparable to the deepest MPF constituent plus the\n", + "# overhead of running multiple circuits; it does NOT target the MPF's\n", + "# effective Trotter error.)\n", "comp_circuit = QuantumCircuit(L)\n", "comp_circuit.x([i for i in range(L) if i % 2])\n", - "\n", - "\n", "trotter_circ = generate_time_evolution_circuit(\n", " hamiltonian,\n", - " synthesis=SuzukiTrotter(reps=k, order=order),\n", + " synthesis=SuzukiTrotter(reps=6, order=order),\n", " time=total_time,\n", ")\n", - "\n", "comp_circuit.compose(trotter_circ, qubits=range(L), inplace=True)\n", - "\n", - "\n", "mpf_circuits.append(comp_circuit)" ] }, { "cell_type": "markdown", - "id": "25f03e39", + "id": "b5d388b1", "metadata": {}, "source": [ - "### Step 2: Optimize problem for quantum hardware execution" + "### Step 2: Optimize problem for quantum hardware execution\n", + "\n", + "At 50 qubits we need to be deliberate about which physical qubits we use. We filter the backend's coupling map to exclude qubits with high measurement error, low $T_2$ times, or high two-qubit gate error, then transpile onto the filtered topology. Because calibration data varies across backends and over time, we use an adaptive approach: start with strict thresholds and progressively relax them until we find a connected component large enough for our circuit." ] }, { "cell_type": "code", - "execution_count": null, - "id": "00b29fa6", + "execution_count": 23, + "id": "05bad997", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "size of largest component 73\n" + "\n", + "Thresholds (meas=0.055, t2=30, 2q=0.01): largest component = 15 qubits\n", + "Thresholds (meas=0.08, t2=20, 2q=0.015): largest component = 89 qubits\n", + "\n", + "Using connected component with 89 qubits\n" ] } ], "source": [ - "import copy\n", - "from qiskit.transpiler import Target, CouplingMap\n", + "service = QiskitRuntimeService()\n", + "# backend = service.least_busy(min_num_qubits=127)\n", + "backend = service.backend(\"ibm_fez\")\n", + "print(backend)\n", "\n", "target = backend.target\n", "instruction_2q = \"cz\"\n", @@ -2203,71 +1274,96 @@ "cmap = target.build_coupling_map(filter_idle_qubits=True)\n", "cmap_list = list(cmap.get_edges())\n", "\n", - "max_meas_err = 0.055\n", - "min_t2 = 30\n", - "max_twoq_err = 0.01\n", - "\n", - "# Remove qubits with bad measurement or t2\n", - "cust_cmap_list = copy.deepcopy(cmap_list)\n", - "for q in range(target.num_qubits):\n", - " meas_err = target[\"measure\"][(q,)].error\n", - " if target.qubit_properties[q].t2 is not None:\n", - " t2 = target.qubit_properties[q].t2 * 1e6\n", - " else:\n", - " t2 = 0\n", - " if meas_err > max_meas_err or t2 < min_t2:\n", - " # print(q)\n", - " for q_pair in cmap_list:\n", - " if q in q_pair:\n", - " try:\n", - " cust_cmap_list.remove(q_pair)\n", - " except ValueError:\n", - " continue\n", - "\n", - "# Remove qubits with bad 2q gate or t2\n", - "for q in cmap_list:\n", - " twoq_gate_err = target[instruction_2q][q].error\n", - " if twoq_gate_err > max_twoq_err:\n", - " # print(q)\n", - " for q_pair in cmap_list:\n", - " if q == q_pair:\n", - " try:\n", - " cust_cmap_list.remove(q_pair)\n", - " except ValueError:\n", - " continue\n", - "\n", - "\n", - "cust_cmap = CouplingMap(cust_cmap_list)\n", + "min_qubits_needed = (\n", + " L # We need at least this many qubits in a connected component\n", + ")\n", + "\n", + "\n", + "def filter_coupling_map(\n", + " cmap_list, target, max_meas_err, min_t2, max_twoq_err\n", + "):\n", + " \"\"\"Filter coupling map edges based on qubit quality thresholds.\"\"\"\n", + " filtered = deepcopy(cmap_list)\n", + " for q in range(target.num_qubits):\n", + " meas_err = target[\"measure\"][(q,)].error\n", + " t2 = target.qubit_properties[q].t2\n", + " t2 = t2 * 1e6 if t2 is not None else 0\n", + " if meas_err > max_meas_err or t2 < min_t2:\n", + " for q_pair in cmap_list:\n", + " if q in q_pair:\n", + " try:\n", + " filtered.remove(q_pair)\n", + " except ValueError:\n", + " continue\n", + " for q in cmap_list:\n", + " twoq_gate_err = target[instruction_2q][q].error\n", + " if twoq_gate_err > max_twoq_err:\n", + " for q_pair in cmap_list:\n", + " if q == q_pair:\n", + " try:\n", + " filtered.remove(q_pair)\n", + " except ValueError:\n", + " continue\n", + " return filtered\n", + "\n", + "\n", + "# Start with strict thresholds and relax until we find a large enough component\n", + "threshold_configs = [\n", + " (0.055, 30, 0.010), # strict\n", + " (0.080, 20, 0.015), # moderate\n", + " (0.120, 10, 0.020), # relaxed\n", + "]\n", + "\n", + "for max_meas_err, min_t2, max_twoq_err in threshold_configs:\n", + " cust_cmap_list = filter_coupling_map(\n", + " cmap_list, target, max_meas_err, min_t2, max_twoq_err\n", + " )\n", + " cust_cmap = CouplingMap(cust_cmap_list)\n", + " sorted_components = sorted(\n", + " [\n", + " list(comp.physical_qubits)\n", + " for comp in cust_cmap.connected_components()\n", + " ],\n", + " key=len,\n", + " reverse=True,\n", + " )\n", + " largest = len(sorted_components[0]) if sorted_components else 0\n", + " print(\n", + " f\"Thresholds (meas={max_meas_err}, t2={min_t2}, 2q={max_twoq_err}): \"\n", + " f\"largest component = {largest} qubits\"\n", + " )\n", + " if largest >= min_qubits_needed:\n", + " break\n", + "\n", + "if largest < min_qubits_needed:\n", + " # Fall back to the full coupling map if no threshold works\n", + " print(\n", + " f\"Warning: filtering leaves no component >= {min_qubits_needed} qubits. Using full coupling map.\"\n", + " )\n", + " cust_cmap = cmap\n", "\n", "cust_target = Target.from_configuration(\n", - " basis_gates=backend.configuration().basis_gates\n", - " + [\"measure\"], # or whatever new set of gates\n", + " basis_gates=backend.configuration().basis_gates + [\"measure\"],\n", " coupling_map=cust_cmap,\n", ")\n", "\n", - "sorted_components = sorted(\n", - " [list(comp.physical_qubits) for comp in cust_cmap.connected_components()],\n", - " reverse=True,\n", - ")\n", - "print(\"size of largest component\", len(sorted_components[0]))" + "print(f\"\\nUsing connected component with {largest} qubits\")" ] }, { "cell_type": "code", - "execution_count": 104, - "id": "3caa3939", + "execution_count": 24, + "id": "0f4303ee", "metadata": {}, "outputs": [], "source": [ - "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", - "\n", "transpiler = generate_preset_pass_manager(\n", " optimization_level=3, target=cust_target\n", ")\n", "\n", "transpiled_circuits = [transpiler.run(circ) for circ in mpf_circuits]\n", "\n", - "qubits_layouts = [\n", + "qubit_layouts = [\n", " [\n", " idx\n", " for idx, qb in circuit.layout.initial_layout.get_physical_bits().items()\n", @@ -2277,16 +1373,13 @@ "]\n", "\n", "transpiled_circuits = []\n", - "for circuit, layout in zip(mpf_circuits, qubits_layouts):\n", + "for circuit, layout in zip(mpf_circuits, qubit_layouts):\n", " transpiler = generate_preset_pass_manager(\n", " optimization_level=3, backend=backend, initial_layout=layout\n", " )\n", " transpiled_circuit = transpiler.run(circuit)\n", " transpiled_circuits.append(transpiled_circuit)\n", "\n", - "\n", - "# transform the observable defined on virtual qubits to\n", - "# an observable defined on all physical qubits\n", "isa_observables = [\n", " observable.apply_layout(circ.layout) for circ in transpiled_circuits\n", "]" @@ -2294,25 +1387,27 @@ }, { "cell_type": "markdown", - "id": "1a983973", + "id": "b578c285", "metadata": {}, "source": [ - "### Step 3: Execute using Qiskit primitives" + "### Step 3: Execute using Qiskit primitives\n", + "\n", + "Running deeper circuits on real hardware requires aggressive error mitigation. We enable dynamical decoupling, gate and measurement twirling, measurement error mitigation, and zero-noise extrapolation (ZNE). Note that the ZNE noise factors we use here (`1, 1.2, 1.4`) are smaller than in a shallow-circuit scenario, since the deeper MPF constituents are already close to the noise threshold and large noise amplifications would push them past the point where ZNE extrapolation is reliable.\n", + "\n", + "We submit all four circuits (three MPF constituents at $k_j = [2, 3, 4]$ plus the $k = 6$ baseline) in a single Estimator job." ] }, { "cell_type": "code", - "execution_count": null, - "id": "83883725", + "execution_count": 25, + "id": "e2722b61", "metadata": {}, "outputs": [], "source": [ - "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n", - "\n", "estimator = Estimator(mode=backend)\n", "estimator.options.default_shots = 30000\n", "\n", - "# Set simple error suppression/mitigation options\n", + "# Error suppression/mitigation\n", "estimator.options.dynamical_decoupling.enable = True\n", "estimator.options.twirling.enable_gates = True\n", "estimator.options.twirling.enable_measure = True\n", @@ -2325,7 +1420,7 @@ "estimator.options.resilience.zne.noise_factors = (1, 1.2, 1.4)\n", "estimator.options.resilience.zne.extrapolator = \"linear\"\n", "\n", - "estimator.options.environment.job_tags = [\"mpf large\"]\n", + "estimator.options.environment.job_tags = [\"TUT_MPF\"]\n", "\n", "job_50 = estimator.run(\n", " [\n", @@ -2337,24 +1432,26 @@ }, { "cell_type": "markdown", - "id": "0fee3da4", + "id": "afc0c029", "metadata": {}, "source": [ - "### Step 4: Post-process and return result in desired classical format" + "### Step 4: Post-process and return result in desired classical format\n", + "\n", + "We pull the per-circuit expectation values and standard deviations from the job result, then combine them with each set of MPF coefficients exactly as in the small-scale example: $\\langle A \\rangle_{\\text{MPF}} = \\sum_j x_j \\, \\langle A \\rangle_{k_j}$, with propagated variance $\\sigma^2 = \\sum_j x_j^2 \\sigma_{k_j}^2$." ] }, { "cell_type": "code", - "execution_count": 46, - "id": "5d2fc41c", + "execution_count": 26, + "id": "a924d79c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[array(-0.08034071), array(-0.00605026), array(-0.15345759), array(-0.18127293)]\n", - "[array(0.04482517), array(0.03438413), array(0.21540776), array(0.21520829)]\n" + "[array(-0.17503803), array(-0.12294363), array(-0.33742479), array(-0.15413359)]\n", + "[array(0.01520694), array(0.05557148), array(0.01454295), array(0.10680865)]\n" ] } ], @@ -2369,17 +1466,17 @@ }, { "cell_type": "code", - "execution_count": 52, - "id": "bff48c28", + "execution_count": 27, + "id": "1071de0d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Exact static MPF expectation value: -0.47510243192011536 +- 0.6613940032465087\n", - "Approximate static MPF expectation value: -0.20914170384216998 +- 0.32341567460419135\n", - "Dynamic MPF expectation value: -0.07994951978722761 +- 0.07423091963310202\n" + "Exact static MPF expectation value: -0.7904923379680913 +- 0.13609157812004166\n", + "Approximate static MPF expectation value: -0.4320295863244896 +- 0.026346772829133787\n", + "Dynamic MPF expectation value: -0.2118021477340412 +- 0.01980723126846985\n" ] } ], @@ -2425,14 +1522,14 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "d751af7c", + "execution_count": 28, + "id": "64360d85", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "metadata": {}, @@ -2441,7 +1538,6 @@ ], "source": [ "sym = {2: \"^\", 3: \"s\", 4: \"p\"}\n", - "# Get expectation values at all times for each Trotter step\n", "for k, step in enumerate(mpf_trotter_steps):\n", " plt.errorbar(\n", " k,\n", @@ -2454,7 +1550,6 @@ " label=f\"{mpf_trotter_steps[k]} Trotter steps\",\n", " )\n", "\n", - "\n", "plt.errorbar(\n", " 3,\n", " evs[-1],\n", @@ -2466,7 +1561,6 @@ " label=\"6 Trotter steps\",\n", ")\n", "\n", - "\n", "plt.errorbar(\n", " 4,\n", " evs[:3] @ mpf_coeffs,\n", @@ -2502,9 +1596,8 @@ " y=exact_obs, linestyle=\"--\", color=\"red\", label=\"Exact time-evolution\"\n", ")\n", "\n", - "\n", "plt.title(\n", - " f\"Expectation values for (ZZ,{(L//2-1, L//2)}) at time {total_time} for the different methods \"\n", + " f\"$\\\\langle Z_{{{L//2-1}}} Z_{{{L//2}}} \\\\rangle$ at time {total_time} for the different methods\"\n", ")\n", "plt.xlabel(\"Method\")\n", "plt.ylabel(\"Expectation Value\")\n", @@ -2516,28 +1609,57 @@ }, { "cell_type": "markdown", - "id": "04200168", + "id": "31effe5f", "metadata": {}, "source": [ - "When executing circuits on hardware, we might encounter additional challenges in obtaining accurate expectation values due to the presence of hardware noise. This is not accounted for in the MPF formalism and could play against the MPF solution. For example, this could be the reason for the failure of the dynamic coefficients to provide a better estimate of the expectation value compared to the approximate static coefficient in the plot. That is, the approximate evolver, which simulates the approximate circuit, does not accurately reflect the results obtained by executing the approximate circuits in the presence of hardware noise. For these reasons, it is recommended to combine different error mitigation techniques in order to get results as close as possible to the ideal values for each of the product formulas. This will show consistent benefits from the MPF approach.\n", + "A few observations about the hardware results above:\n", + "\n", + "- **Coefficient norm matters more than mathematical optimality.** The exact-static MPF has $\\|x\\|_1 = 5.63$, and its final estimate ends up far from the true value — that large coefficient norm amplifies the residual gate noise, decoherence, and ZNE error on each $\\langle A \\rangle_{k_j}$ by roughly the same factor, swamping the Trotter-error cancellation we gained. The approximate-static MPF (capped at $\\|x\\|_1 = 2$) and the dynamic MPF (whose coefficients here are similarly modest in magnitude) avoid this blow-up and land much closer to the reference.\n", + "\n", + "- **The dynamic MPF is the best estimator in this run.** Tailoring the coefficients to this specific Hamiltonian, initial state, and time gives an answer closer to the exact reference than any single Trotter circuit — including the deeper $k = 6$ baseline — and substantially closer than either static MPF. This is the regime MPFs are designed for: shallow constituent circuits combined with well-chosen, small-norm coefficients.\n", "\n", - "Overall, the approximate static coefficients still give a more accurate solution than the product formula with higher number of Trotter steps with the same amount of Trotter error in the noiseless setting.\n", + "- **Individual product formulas are still competitive on hardware.** Note that the single-circuit baselines ($k = 2, 3, 6$) all sit within roughly $0.1$ of the exact reference, while the static-exact MPF is off by more than $0.5$. This is the failure mode the small-scale Background discussion warned about: an MPF that mathematically cancels Trotter error can be *worse* than a single product formula once hardware noise is amplified by $\\|x\\|_1$.\n", "\n", - "It is also important to note that in the example that reproduces the experiment in Ref. [\\[3\\]](#references), the time point $t=3$ is beyond the limit at which it is expected that the PF with $k=2$ behaves well, which is $t/k>1$ as discussed in this [guide](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html)." + "- **The chosen Trotter steps are partly outside the safe regime.** At $t = 3$ with $k_{\\min} = 2$, the ratio $t/k_{\\min} = 1.5 > 1$, which is past the convergence threshold discussed in the Background. The leading-error cancellation the static MPF relies on is therefore less effective, and the dynamic MPF's tensor-network reference for the \"exact\" state is also strained — even so, the dynamic MPF performs well here because its coefficients adapt to whatever errors the approximate evolver does see.\n", + "\n", + "The practical takeaway is that on hardware, MPFs should be paired with strong error mitigation on each individual $\\langle A \\rangle_{k_j}$, the coefficient $L_1$-norm should be kept modest (use the approximate solver, or prefer the dynamic MPF when its tensor-network setup is tractable), and the Trotter steps $k_j$ should be chosen so that $t/k_{\\min} \\lesssim 1$. With those choices, as we see here for the dynamic MPF, the MPF can recover the depth-vs-accuracy advantage shown in Ref. [\\[3\\]](#references). Note also that individual runs are noisy — on a different submission of the same job (or a different backend), the relative ordering of these estimators can shift; the qualitative trend that small-$\\|x\\|_1$ MPFs do well and large-$\\|x\\|_1$ MPFs are amplified by hardware noise is the robust one." + ] + }, + { + "cell_type": "markdown", + "id": "5ac2f8a8", + "metadata": {}, + "source": [ + "## Next steps\n", + "\n", + "\n", + "If you found this work interesting, you might be interested in the following material:\n", + "- [How to choose the Trotter steps for an MPF](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) \u2014 practical guidance on selecting $k_j$ values to avoid instabilities\n", + "- [How to use the approximate model](https://qiskit.github.io/qiskit-addon-mpf/how_tos/using_approximate_model.html) \u2014 tuning the $L_1$-norm constraint and solver options for the approximate static MPF\n", + "- [qiskit-addon-mpf API reference](https://qiskit.github.io/qiskit-addon-mpf/) \u2014 full documentation for static, dynamic, and backend modules\n", + "" ] }, { "cell_type": "markdown", - "id": "78e91ddc", + "id": "70be41e1", "metadata": {}, "source": [ "## References\n", "\n", - "[1] [Vazquez, A. C., Egger, D. J., Ochsner, D., & Woerner, S. (2023). Well-conditioned multi-product formulas for hardware-friendly Hamiltonian simulation. Quantum, 7, 1067](https://quantum-journal.org/papers/q-2023-07-25-1067/).\n", + "\\[1] Vazquez, A. C., Egger, D. J., Ochsner, D., & Woerner, S. Well-conditioned multi-product formulas for hardware-friendly Hamiltonian simulation. [Quantum, 7, 1067 (2023)](https://quantum-journal.org/papers/q-2023-07-25-1067/)\n", "\n", - "[2] [Zhuk, S., Robertson, N. F., & Bravyi, S. (2024). Trotter error bounds and dynamic multi-product formulas for Hamiltonian simulation. Physical Review Research, 6(3), 033309](https://journals.aps.org/prresearch/abstract/10.1103/PhysRevResearch.6.033309).\n", + "\\[2] Zhuk, S., Robertson, N. F., & Bravyi, S. Trotter error bounds and dynamic multi-product formulas for Hamiltonian simulation. [Physical Review Research, 6(3), 033309 (2024)](https://journals.aps.org/prresearch/abstract/10.1103/PhysRevResearch.6.033309)\n", "\n", - "[3] [Robertson, N. F., et al. (2024). Tensor network enhanced dynamic multiproduct formulas. arXiv preprint arXiv:2407.17405](https://arxiv.org/abs/2407.17405)." + "\\[3] Robertson, N. F., et al. Tensor network enhanced dynamic multiproduct formulas. [arXiv:2407.17405 (2024)](https://arxiv.org/abs/2407.17405)" + ] + }, + { + "cell_type": "markdown", + "id": "e47f668a", + "metadata": {}, + "source": [ + "\u00a9 IBM Corp., 2026" ] } ], @@ -2558,13 +1680,8 @@ "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3" - }, - "vscode": { - "interpreter": { - "hash": "72460b19b35c51a2148375679c8e282bc3cd3c5550c209f0a38b7d09cded82d9" - } } }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/25ce07a6-1.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/25ce07a6-1.avif deleted file mode 100644 index 692112f6ed2307589ce29b9b4da3d7c4e0b1fba1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49570 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ΝZH7i+7{;bntVZy?VsU12l2 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 Zb4=66_C5Xo{~!Lx$$eeV?8QLG{{vY=^n(BZ diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/2da9c948-0.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/2da9c948-0.avif deleted file mode 100644 index 68d7536c73e7c2705e381d6db85553ad2054fb86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11848 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 diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/34bf68ac-0.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/34bf68ac-0.avif deleted file mode 100644 index 213fcfe1a319e57401329159f35d474cc66587ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8505 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 V-z~<;vP~Cyv|F5VdP^MQ{2xn12Jrv@ diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/35042576-0.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/35042576-0.avif new file mode 100644 index 0000000000000000000000000000000000000000..c26b6ed1c1362eafb217329d01dcadb228d367a8 GIT binary patch literal 9201 zcmYLvRZtyD(=G1q?(Xgc_l>(lVB_xY?jGFTU4uh#m*DOYAh`2$&beRRewbcsb$3no zyi85ifPjDyn7Md57`s`Tfqa>*r5Wo#*w)hci-S7Y0$q&%(Z7t;!qmp;KL`TiU}@s= zKm0$B`ne*;=&+cApa;Jpeg@(5D+rPFYU|7`~RnauzXP-OG~?d z+xRz%`9*;LrhQc#yRoqTQ}O@BugL$zI!gy9hp%9irGtt6mq##mV-*X8K=`Ks!_wIS z_zwU90dxE6q4x`*I9PgE{-c1yz`%UD|CdkjkMuRge=*R1B0R>f9%BE(-&c;Mjis@ZC!ev6gT=q+MQG_@`!Dz^{hA&;5DXjy3?c*! zGVDvhvvdOfH|E!NU&S{69?;j2WI$U}V;3|KI5=D?YW-UX2o5|Hwrp`g09dmxV-}uk zazUe8<2sCJ)uMTbMA7;+h3K)k_K)KR$hNnxeg%T$cfBijZtYu(C}K zw3hK#PH%r0U5W46`zw#I2xOV~k(H;;(B^d^%Vn%a#(A^|Hzy%3QMO4r&bcSmrt+PW z7@IoBA2_57ORqjAa}e>a^Ppye;u0r(3y-AF7*Se+w+nslC5d$WZNM_6$3E`srq9Lv zw2=b9bs6h}>(Tc1bKhS-rLiRkZr*RbtI&YG%xm!wB&(M_$HW!Kf{HQaglCP{#kmFT z4EKz8swbg?mUxnSq$d|2vyGnldg-$fDQfx;&&d7DJBesaDafM17(){U4V;c|Tp0D< zd+Ja^xpNH50=@kg6X&}j-N9zA_w0ndPMs*pL}xUH`yn^`rCb$ULIxJ)`BNI4ZN693 z`|JawwiGz_S{r(Jge4T;tq=4x%AuvHDF^f`F)F$g>+nVhp7^XW5Y8L&dE0{t(LWB* zW~Y-Ra=YzEn?50@-e=L}es^}2CaR9=j>*D%}E#-GSh5{_wp%_mhv-<2P?B>)6D?Q`>Pe77LfcM?vLS$ob z8?sz!6rJQC^=buvK*+}@h7MrwYW|!z&2-P`9zNeuHKZz5 z074g(yLL#S%i@Qp8MOR^k>&>U?{wueF0kxVh{5$&Jln;%aAx28oFEtZK22?1Tb z9`3MO>@G!ivQJ4js+L;g zeS9D*5Xs>$yr(<7=yjb(7SlIQb#uuzHyqvQkqhg*(3u7r{sA0&0s)HIOu2&{EHy&_ zX0~@;{#JxUPESy|z{CQ^uyW(a76@ZBsu#YQ#Q{OKBrRr$&L6V`=tmm5MH_ul=XoaL z1}oZD-M9MEgNtg?&cPdBm|hSki~FLgx7SGIORqNuOE1Qilh(1{#yd*F@1e1AU~c_< z?K%P5kNmMu3Hcs>(^Z`Ez2p#Qqp(qqh830HwZ?IQD*_AH809{IvxuZn@UBvp5#E`I z=I>W2s>asWErX0`Bwf<%TH5no?MZIBI4A_B9N7&m-JX{Q36-5pgRQZQ9VFtFQw%nA2CZC(z@K@nq3S4+k)3zx2v?0Gbb(_bV%?`$Hn zky#AfJd<3k&idDe5zj7K^+1^4I;jLOLLy0uHmZ(%){Ph*jVUdL=?> z^6a1BfjX0EjNOb?P+2D59|(9##W9~*crKzPykPv^6%d!fk&dXwfam&4bFZPZFwi}O zcWsSI)$Z8U_S>E0w+cy63d2OmsC#2y;h7 z43))Xp1y;ki3)tk()<202qUXxdsN9?Sg^8UsAk6-o6g@4rQeU_8`SZNsK_jgR4d#5 zhLqwY-)+y)cu$t_DdXJZwpT=^&|wP;!8*>stI#pEf5Pu{D$07Nk6dMvfP+fX^fPsx zkEORNh|?bhEcEuZlRc`cku3BlJ|gk#pFrYpRPxS!ulL*>^cDiiu3*yJw`3TdZf7{P zts$nF?%!c9Dd6MKPFBJSZaoY**Y{_u8Ub~|D~-(c#p8E;Ab;gdV(Bih%@Ygsmf`ak zg7!CSviHQZkBG{7QK-FHxRxM!s4gmZ*3>bc-qAJAoE|g?KNDH-$?4D<8(%m*SA~*b zWbxI+7t^FHCYBr4WA^|2jPvYQAC`3hnuJL(xkrYt7`_b z+TEe%_K{QIQx>lzEl8PV|H(zK7x;U%MpLA2K7mPi#>NMkBlhDZAfQWXuV*LaEvn3yA%+R=3lUF|)c+r}f^Hs4|u^rV{8Lrpr zRd~PAB>S)41=BrXSqQlc*>DlKG~+Z#(`D}?9k6Vy6B(o0b;s#h$&BIiLuJB?pQefd%XEEF{#U^G1EO|MqlGYx>>V@-N_CHW87v`3wcOAQZwAaS?E zg<1%U>{3-S!tq}I0%I5d=4(Jvy-QK?$2s=Gs_Mtz2YZCEMjLOsPad-|AC@sxwH2Ya z>2dU0+gnwV%v7&OihtigAGTw_9KHac8P{1QTrOsv??E(*PT_U7rN$jk;=alQJJ#$L z%Z%2te8QNM^0MP0s#3vHCLOb5DQn=)P8D6@qb|WzQHSL3FF~dFr0J|kM>TgPXKt`u zTNR1T0I1fJ<_N#lw4JKd5j^2p7^EXB^fo`6*h?Fk9jaAnm}m4uwZ)d$^-$bv=gkyD z^~Lx?GA>&P{@5i+`SsVO{GiPz!bng!P)vsJqCH?EG9&P}ggi9f1Z_nO&jQ;zi3I{Q zZVr}De-Pc7#ir2{0a*bD(pvbF$Hi^N;r9rBS>G`8EctMwbRhWZIdqEsz!pS20cT~T zNVXHgO!0`LQc+@r*5BqUnkTR>)d05LKbz?Jw3W2-uN1{B;K3t%DCI4} zoTLy#I=s)pk&^_5b}k!1(_GODQ_rzFS+WAL9zH2UN^d030ydiAzCsqPR)l1j4>NgIj{GkMt` ze*MIP{!oj#@(-~ep9+&m4eL+;WdWU)v3=VZr)<+Lknn4mk=_kD@B`yVyXE0VUSIu^or-K|BxNr8f0q2a0m(|AS2LvTWM^ zx83-ZnmG{o=;V%I*di^i_MJbFe_N7#FgdrUy=4vE(GBS?@P)`GRp_)gASVGr{rjMP z>UGzPC>^=S7dIg zDrWFQ&H;v)&(@^2!=GqI?=LoR9mf=09lHa$RTq7bQoKjY*C5SdzwGF)IAj_dBMXc9 z#F?(oEFL%YvKmRe(@bS>&dC5mka`=x)HUjKzmJ=IghH@Z0g=fwwLSH8>+;3V1{Whb zWz615Uk#-UGVMPtgQW6?=_<@n+y(bGf)&RN^vOg`*9kP&966qldZ_kGhTgmDpzp>K zyM2I4tKEBHL#3I|$cM`zDBRww0f}g}jf;}}4BRgBEG>OLTv%5Vy@$7%V3*7pwONt+ z4ICnJEh2_Ru5sDraO^v+{kpN@f(HTe-q5&KaDXWe0_Gn?taPcFaLilFd%-b?2}FZt zv3pJdz_iTmkP328wyOc!E%+Sa>!xf9uD-Rsv&n0WSMs?|eisa;-8pfcRPDNY*|`2G z^k{t`6UfdnE|NFz(oVUEv0CDfuA(Qi`<+LU@Hb4nryt!{cjDuxuPz@hr{76s^>8T_ zB_}zLi93Qz_F~qNgBu%B7oJvAnHVOJTS4Nl%c)iboJ1o2_W7if9H7bdhT_pjt^tDv zy;RaGR63sVRo}}X?nikP%@ci1E!-a52B&I)>I#H|Nc(zsspIM(d8owrz~7vf1P)*U z)yAr}0o`t)-obMWwX~k3-DlR)fIztTXUj~h(44XI1~j5 zDEqMeZBDo5mZ)L}27)ZD@LIJ^8vQF_T2kChfE%T?9ij6Q+u?u(eXK-|b(fC>Dgecd zAi3928e2}asOiQh)n8%at`}HI%iD+4eJNxiTJz|6HrPtukvz!4P$@3pszXn|J`OvJ z$#-~wGPv&?BP!rkQx!k+Zb-ZhCBBMFNW`&y5$W2Rz%oJkf+hI?mvuewZvw~i8FTYB zA5J+bsX>*Rk3w;-2iO(~YvkP=RjcQbr~H2YCqfZ=62Bts(r!jaKlFALd|kktLS< zg*3Xpe$NnbPgBa@H@Y@$XY=ZJ+Io>))tR{@OW#mA4mdCI#+JK5@5@Hs&`vx}g3^4& zfhHm0yFet1swzz=_Y(vGI#4kyKlFk};aX(iWWM-ozplTfgLj>+}`4U2u-VohciL#{oHJs*ugoM zG6R=cU1`E7-@CRgra@iaFD4C;;SZIfno>Hsa5*3%*~CoCxlP8~6>^K^Ki{tACQCBF z?aynt1hB2*Lfdarj@xY?7i1>`kVsDf?TuE@LapNK$dnrHlzCY&99KdUpEh8cnh92BYC0YXu=dBWXVd{hZQ=`?e&GN2#c5g#h(x4#g1q>v`|`Xh#8L) z--F}SqD@SV=2cOXiha1kgxobgby^Hfl;uLh>2t3L%C+{Rb&=DwO=r<-09J8`Vr?nN zZ>0H2ymJM7lQgeeRqZ*2Q&R=uczH}#Rzs4hKY}47SiW@Ky9VhZ8dDjw5ch^spAU%T{VR@9UnHi@o*bflJtPYpqo!hQOFw&-{bInZQh& zTF5mvRVCFh}MZmNV)Czn#-$ zdr)wtFdxLjg&eI$&tMBt-UV$t!&V$_0g`y?6@Y%^A1} z-G3t9Qg-S%F69h<3X47yUSVo&*1b5Zgadjjp+j=(4zHHSMI@Lv8zBM;~BIvB=&LjH>R;?#1w%-A|?*Ipqy_v$}lKhsdWJwd$; zQdV+a;iS)FfeE_?OG218?4QvYF;+ePbCLIzyt6YtzOGUERsB#L9|uIj4cM)u;J&#U zg^G^*B-0X$_D|nUpf;>t8x1xotLzwfRG1x9h2%|ZRnyW#fAe(FaYM0f!QOJnY5NY6JQOpYKABCRi!MP6~HnC{%Iugx2(t7A& z4MP11@(1h+uJ(TT>~S0(^XIWT!!eIT0p60|+gzm0O4cUI9wjJH(CkWg0qfzWztf=+ zS&ECNyiaykwZ&jUc%n@E?MPW=uy+&9rNqdU zyDyDJv%1{f_N#Ey?^4SYRP#06$zMMuYriSo9==#;>}D4WrHLm-h4#wz@ODA9L^Kpm z{Q;O)?}bi3-9^{)C+EiPF(s2Os5Lty=n*$L9@2&GHp8}-AMvm>tL2C!*BS`eL=b5) z&bgapmhiu;>`cF5j5cq}6PWp79W<7k=Ox-h$@@5Kt)3%_Z735&T zTZ_jw{Nkd!^bYyI3CP@&O9#{ zu^CgJ06WA2yb|nb`DQs2sV$*KTll>}Z%b{pD^e4FsfFD={+h@X+8&zgjwC_{oNS*3 zX@+B|8kcykG=V9h3Jzo@`OQF>6RJZ|fAgq!0}GGnfF1aX{}%ATon$(# zT3C3l77(fKN8oGLQDq4T3gGG3thO8>2sdftSO zJr5jWhran1kHVH}zShl?k~7!Kv+Bp~wHsQd%N2;sx3xivghhvFcTJyNnB3G$wf0sE%k^d^YA4EH z)&NuuyZzCJ6vLzq(@+<_5V}NOh|NV9YDr}|QcY)wkAra}!K!+M)SC@@eC=r`v5~)c z#_H#4fP}iEQ*TgC8e6efxXzmN%7)5_xWtdlW2di}9MFW1i#XR0zwx7rH<~agoIJV? zP4cs!+czl=Rt7|ghN%kyt;YurSOLsNhDG&ANQn&`>%w5 zOaIJg#v2M{WcJ5S@$b3koEufITvmAP6r%F)SqaVchg-h|Q;>&TpE^Ma%WY;@jS4_& zY*72;Ew;CCsm))dt8HJGjJIqPJ9$E56x!b!?${>?8t;kxrk557m7z!^6MHs^PB$Gr z{*7*1V5+GwpLb4&2jf$BIuhG?q>EX73N*c)VtNCpV0IRdl2y*VFzgMe@mv zPhK6Y=U)o?r4;y~OUK1~+CP*&ec4SKu-1i2iNw3P7f1O2K)ndHhF3Yrag0#0{xK%&Icafh0IDTrQE@U5xNv@xR?0V0fMETrK=t~7i zJ%$zVNL;@ly;~j;dLy*Uc6pEm`$}#BNU|3l`ArQ0vBATE*Vf!12x9uXmU+)y$C2o4rIg>cUnOunb9#{em4R`n+U?G z0u7X6bReUOq*0KG11V~X)pPX516j(tWh!nPaE*U#QqD*EYWw6@UKlnOC5T#U60T74v`TtZt2yu zVIs~WE@fM$U(2(EeS<^m>)y~xK8Ok)o=XdhT8 z>Ojg(UPl+y)?2qX)X&Zdml&L1WC@3cvoDiVJz8hN*I=52eNRpcEH+-OL~fj`r*{Gp zY(1!n#Jgx#rn<)K);fhXZxfI(UThU`Zdna}r%rKx8BqF^nYdyx2 zZwL*=v%`>C@0g(%Tg|O|e4+tc)b$@1)yaK#7_{-a>nc^_WuG`L#Y#%x+=gbuwl;G0 zxIboV<7aW1V<&S};xBR{Q}uy7xPn=5CN=;7+^`#J;Y5mwT!_J^OL$S*0$WY|+i(Y1 z*T>kUBf$pdJZk4uZd<$4l?in?7CL`w;^Z#Oq#!@Wtd88b6Bzh)YdPxqrP9IXW6L3@ zx`6y?{jFd-T=+i(zm3T4G~eR<(gd9we2yQj+Rig{?6x&~sA;utHYk#*^J)(dX)g-qIG=#AP`8h6XiIPwQm9w>f`Xmh z!!R}JT4>_PK5GG`n#v%!f^i~?&Ntu*^{k|Q{6+#nRiJR$+V>*f_o^{fwqJy5KSZmD zcaNyOT~0-!RV6_dSdWSTYsFzsGa`Dj;n8dme9s|Xf(zIIGatt?Jo$_y>_b@GN!cEy zw1cE{axFY%QHVr$n?rx=$*T2g;q!b4tJq9m2ZCvy)2N!%kJYr=e^!lp|1r??GAIq> zI1C$*TC~23<2>6f%v?OXO5&Z-*K8KfM2aW!N_XV*aZk6k4eUtV-?clyxS2@{r*2KF zjWnGjPnIJRYX)H*I|+<-;rp^Gi8%kl6!x*gW3`ISPlbGA2KM6p`^a z2?h~O=&e&j_-1(5TnD)gD$n~Z;bICZKZ1V+`nnP;YPv}u3=F1YX=q+4B6;{BLLC=| zM*lOP?yq%xJxB4em;N(m}amX)eUt@ZU^KW^@_G_*vhUaCOj6vYn@3Gz$!@ z;)7Xlzt5l)AgT>5{HuygKEntCVSFF{fLEvFm>FE<1^b9)!=0ad$o{TB%b+@SYEE1s zH!XtBP*ee_YGMo!c}Cv;D%^&lkxSpBR&mg;Jj{F&Vg;yiMrr7uHKytS{W0Bv2}Q4- zmUP~szZI0WEI|@;K%VfkSu5dN?&hQ6T#-@BC{|HlldXw0;ZQG2>p8?V1VTVbRy~Gq zK!*J9-ri&a97ka9v|g9EitFj_2t4afd`%PQalk$>v&?7hIB0YkN_`vhE)+Au5;fk?x+9D!0XfLGiN69FTGRN#xq^mFp~0e#byi@gEIjC zhdoXZNDvk-aglZ2(O7HJU&|Ksni6~)#(K%ngqjCrLDpE1u$IW0Y;nBUu({d=A(e3I zSlZ9*f}rlTx>Yh6(tV7h?hhjmVi*#kGFaH@inm5*<}L%gi1xL`cv-e(46)Ia??4|GNrGaNzA{87} zZHpHcsZOj> z|G+SMVyA$Q@xx*f4lN;^hTFWJ;;A_bl@>2FoD*7?KgFXfv>zJOQ55m}y}>&V#MKfK zGq;L*zWUgL-3K$)l+sG!NhsH3xrxz%EjZr|3UAF+_#VxoZgD!RK4LJKC+76fm7aG9 zd*CBD+|D(SJrInej!+#I} zfPhS${)hjU(IFrw@V^A+ZRG~p+L`{tq{INQfPWMKOx%C@ZBL^&?JdZz{-*#q-Y6dk z^zGkc{9DC)Bj*3My}6BDI5_`t{D1MS@;|Wx1aW}86~jOfQ@gi}YV5)(=?jPYj{z6t z2r>T$006KqZ)a$K1DFty8|WVeh=_>zmi}Kq=|9rj6#vy={;BX8JG)8#BRe~M697ZZ zE&p941WZAu5CKPbM<;Wzqrh7a$QESm;4WZn3$gn5zQ{lj@W0^A`Zhh#7ZwPBg$sav z7xX3&gB;BN8}n_uH?!@(7xXqHX%g7X*a;hej7&sF|K$=6j++>hYn)HX2e$S*YbvpG z%-^v7r`$PKpJtn^K02=AAz2RgG;c(fP~TS)lqLn$@#^3qn)i*PNTz=5Qp*G$#U}Ig z_Jf4KCv85FF3SR@OfdN%}3s*MQ;1g}6Y&b8BGAIcv~OF)bpGrH-A}^>Rc5C=HXF zg5kwqFtUcPfc!g%n1yB><`DgToS_Ghvv)yrduz@=9r-+%wpX=049n?J)9g{orKx`*HW|O&B&_VNRo(p~S6v2!W$Xzw7VR9=Ww0 zl20KW77ul})r`eD-S!*N;%On{a0Xbtg8Rr%@f%=4 zOt5=rxu}1$@3WBSv;#gLOgVTr=usFNrc+m!d0rPWbq1d@(O|HgdWGbQYx}TL7 zazZ#Bj)lC;VT8d6?X3}T3WvC-Ei4=tc9>pd5NI)@wpQDq)muFLkV=7sjT-RU7)xz$ zd!RJnFqB=f$$xxFiAm*P=L0YkZ{W=+p?iTggcMnd{(0~K#|ov$(dxE}H7`gzQL(6- zxZBA&x<$#}2{gswm8@)}hKG!~tJ(_#j^S?PYBZJUr5#U{^2e=GnBB>$)tN7|OtOI* zM1l8V#OJlfRgt|m1gzWY3p=xWu-aM<4@ybb8NT#G0;An)Fw#te=_D1Ej659|rwiDn zuT7KTq2w`X1wO;sib=^TvT9=Dla{FG!Ws>MMSs|B=a9wnsbr&?lv>Pwhv#g|S_>B= z@GUFw<}kV8+vlubf|l&MeuSgzjzv8EZTXwT!VLezGl||N=8M@*`M1H&KgM7O=5p19jSE4~>Sy@&VNkYe}r{fJV2K|IN+JX^45XMsu zohfk%m;U(aUWF#_z%0|w()aynF-%4uy24k1gxEf`_8dxg$-hKeYO79`QwL(pEQ__O zc;M~E^7?z}nqThAa;XN&jgwHAnN*DY6rd(+3Zp=886%7la9#N zI->B8H9Fc1%5lBkj7}`hZu~9kKs()(qYO5(qJhPsrM1s%&V(u}L(!Ebqu+@*a(^2Q zfCW3jGRp8}VfXitWggvi)~K$y^~XtA;dqNvZ6~@^_a{UJ>_yIx@pCYuU$x6wy?2}9 zXI7T4i6nfaB=4m(o2jDWdy?sq-o*XY1y3nrFZ5-(sLEqrA!-b;LSnkrOtr$qXiS3$ zvTiaXaXDx{j!fZWM%&?sTTdr%@I$4!1VPrjHR@M?wmqS%r zz$3xnnwWcf&igNV%E7)th~|$MtJE3kl(!+bh6XAiLEG?(+!O_d zx(!0qlh^g`Y#}PyCoip53Vkc6aaN~p8Esj%sH*Z5^MBuQ8Jyx^v8fJ4c~8U(g6_^@ zn{eyC_=TFg1$k$7F;kqsgGtkxR~HIo&wXm^Nb&>ESa-}+UbOwW!CKvKtnL{Gc#IsV ziDwAiho%qhD4@!R_aY*sh|wS@y`m42?I`k@FS61`7`sca5@@77(=&j>FoBc9{D z9mg2=uo{^{T(Jz7K8n{nk;LU0xd~N=ccKPyVVFvwso55)?*f?}xLa)ImQa`z7`-K` zVkY1B81}^5i;T5ZK`iu?aBMQbt0)L7)g+!V%DE`Jn%gen!u}VGs#n4Tm&b$f$azUR z7KBF!+dpEyxFD?PF?K1wo{~I(FvJe-FSl0HzvuPxqTrH+b1hOftzS|pj=9%Iq-typ z+B;%PsU3D%%l}Ma6jT|TO0M_1Ec@))sI-vy+$3yj6$7kE`4pFbH)L81o5wd;Suq*C zuLeuL?OoSM!yO?1abDkP&cO8dz^))P*f; zOMR%fgx+Qi3a_)OAh`h4-08M1qEZiAy+l1(6@BCyJ*2)bej%f}B_E+N!l}BVxm?p0 z{9T2*0$!vSYp~rrX6MtPpJV%s%fgw}NQS$UA=zhnlSuTbHY5c@G(WW5X4QRlqrZYM zy<4{&G*Cab{@W0TZ%o$_Kh6_%7H?XM!ogZ--)|oIs($^(BA8B{9<#y%_O}@*gZLIEK<&#*Y@J9I}ybBnu~ZR$%F#8tcl+|Ev?UNkyA5>DZg0X zI<))e%=GE?WqSo#G$X&cX@&aayn)B?_3!9~%V_ppRIq8)hon!qIyQVDbzrhc{$VcF z#&Oj{Y~uyD&EFPvgE?lMqQE+@Gs28uO4}X4?i_GPBSX;1^R`d#_8{8Wds8n^y8v`=AlW>MwOj zS8|M>CxdI`_qYl|?qMqLFK11yS)RcSFv#M=VPs^2F{J1yV>)PN-2!%jT^1>lS{^p6 zY>m>56}tr^Jg=kyCt}O$yMAO)Z|&3@Ull9pZg6pVJ;FD@xZemya`J7a%ov6-_#2;; z&Io`5HgMQ{mptY)jwQGR5fLW{PE@GXHCXU67+JRdW;XZ&Z}X)^UIaWil3xS(KDgLd zRnT2tHi)i3?wGG9;mBiWNykbkX|ZQ1ScpgeXBV%tMu#7Z$CqyAZX~M)&h*}7r`W5M*s1d$oU~+V*ePi~NtgXN%wf)-xi-P-#buq*>hLLz z99_CHBcdXw&Gi@al%mn5A36#i4)2qLE8xW)9Q*A5$g3Z@4mxPq$4A%xPL=GTN~=uVLAiu zX1>sE72zR2WL#q9(KA1PN@@ne;qS^;wAmP&hkkZ$TCxz<3&cUFKb;6zqVXrVBK)#v zES1+rhSZ44?8#$0oKm*`SZnCB^|R&x5%M+hWxAE@_%2l=&A%6#s+iP+xMS+uB$~#O zSsxa{0@G0ks9h$}CfeLuvbtR*v@}PMyT&CeoA_2K7eDph?-*<{_%n*VfU)z(~ z6@3t@fi6oxzSinP7#f&^An75!wqzfI7%lA3)xQgB5X`|%9;JF4DW2a7({ABI#haJC%$5Dy`{RoYqg!j?ccnI2DNpUq!dJG1*{mOm16T!XZg5m!^*s^4B86})SOa*GpG?fy zY+cvMVIo=7B8q>8lb7La*NbpZ)&_cIQ_@K9=)Ze24vEVTVp^XV8FE~8sHLWyq{O)6A&VpguXdn`V#ku>l2uzgqu?F=Z z!^bXB)$2byha(($$?TbIx6xQgQvrg;s*c+gf3%*G+hT7qqmPPcc3g8J@J^v&`PT6l z`O(ho@|6)|Ymeg4*S0q3ea`gX^`O7;az$gD?|;a68g`U9Md~v*l!M#K^2-M@4lN{G z3s3kJ`Q17z!Q)52Shg88_M5YxE6-;yoAwj1U9g?QY%7hnSwybk59JK)oO||_SaI;( znC~Oh?6s9uf253Q3RR`1fcrtJimVVfQd%NQrI|0})HY{N-_sf-Ugt2#qiEnyqj0aJ^P{ z$08D9xCc#g=??$3+Nq;It+eO$qn6)I>R>Za+G1o|4K4$bQRuW~bM6=?4g%yHq zE1b9{&yzdp(IR@slmi(Z6%%Y1h=XsdTa~*U#o`ZxaDTUb5ua|egCHfgO=u%^W|%ZZ z72$_^bTudEkr^fV+u7#f%psk}g8K*8;xvb^Rsqe&D=W7M!Y6{3Hzvhr`2=0gA&;+= z5DR;d)0U>U!ZyX!y@?jf=s1bB3~gKC{am$P;UEKMkwoviUM+{&YND<{gv(N_PPOdS zm-x|y8+AykHzNCQk=aAmwvGvT0;U7CY}(z@`0!O6zjjLGEGV#!@gd+~hf=hIUjetG z8xb;nNaa`j6(M%&5BBHrj}_Nwx31{yY{E@&t>f%uXE4K3mT6`T6=X{Rdcv(_3hbOE zX9vVO@Z+A5iXV@#r5rQLcYaB(F0lG70Jo@$1EbQHiRea1ZivbF_U-p#NZyGD)fkhB zR(!WevFs(E)Vb27>eY20;41nl&^2SE})Es|f& zi4q@S2%RK4R>N>513h(1ZDH1(6yxBP;ciBJS6RCyYD2={kMt-)no8 z@)zeGT2HdLTi+)?*s?l~J_8(lHVp#kL>UbzsD+hQ=@p&yY00e;57~wfND0z=XvAC7 zf3P9Ds~igYCzX_5Hj^CWoYi9e;X%U1XqAwPbQ$e(x-ub%(lN0cZ8lYsgU0KndvzVj zUh-Z=DrAF@*_xFyWEnn=q zrJoDJRGz<%k@YF2mQ3NI%4la3x%YYlFrb@J$bVC~@1m!~)Bj#iXAKYB37vUt3@#*V zN}6(iRQgK_{EWbBh3tdt(meZzYz%yc-E3gLL4?UWX`M4&_6 zw#9E`qxkw^M}jdFu7ZFu&foI!m%&fjGd-mE2fp%c`*=LlKGgElMKN z)TD+=IW7Yw$z?oU{Bp$zmp~(<`l`?WWA6lI2wzpAl!nQ~LD$p~;n(fR^yNY>I*0*$ zKkuMDr?1?=nMjEq++FHae01Tn4Q~;lhsqkvY{cL|Boa#YDj#G;k>$*ib*@HT6;l&_ zDIJ2YH@+6*-Q_^BG2a>FT-P2E9+lQKYn*E+L>5m+6p*wF?X5w=AlL!Mn$NI$$Mg#O z-Su2(wQ=SOS(tJ0@o18~9}J$|WDh=0Jk~%%A|awF<=y{Tv#3LBqHpQ!NKmi9_oCA3 ze4ExRT5iC#T@UC8ETQw8?@$@Q^= zQ#|!*f?lrhfp>Aab-<56JY_rQRBh9n*H!Q9-9hY*W4;8les%yb7I$P$vN{+d)nh^I zwXkT@By#+F&z^Ud&NZHdc_&E^H-ofd{G;+Ks`}r4{7SO7@-ta zkFr30I;$vdo$t39!bU9G3Ga*SeK5b~hkhNhHS56QSVQ$K9d3&jF;-@^BOeDMci~}@ z+Qk$?HFK*qB!W_!VT|x_K6Jga?^jotGz1Yhds63cERSZ57d0KCAu&$zG)}JPrh)3w z9P19M=o=pV<8%bGmTGMKhXiam=_1_nk97toJ(JQ*tjQJvNx3(=9gC~bPcv5K5x{%C zBGn@uKMn9hJ?B4|RhVrFnm*!33|#@w+}Ge#IGar0J|wNtU*@W*({7}=Mz@2O(^YYr zJ-6U#=clw&~D7C*u#bjpINv!?jR4|x})X&O3!#z$>{#bpl>{6^~R~YF5 zTe+;Q7eb|WNQGh?J1l#<;W?ZzF8I6d`3hDYNm!;HSLT`lqGZ&i4Q>t|X?%C4CDa0CH0_6-HNZrvUftEx_%I|?VE6?GoqfV#b9;ojf}`TV`6@V9 z*EJEZV$YmG*V((%e_u5Qu>^scJ1#!`;bIvqo}3VS>B}J@k&!tQBDu(i@vG&2Cns^& zDh7${s|C&vgtSM;%X&G0y2M4QDs<+Z1!DVp_(AgqoHcyq=_&R})3R$T+RX;ECK=mR zwZ0?@(q%9)YJ6m5rz%&t_hBZNUULa++=AWIq+lqpn1{W1i2vc*4-oQ~Sw)r5i<##q z`F1#pXQtB6QM;KR{L%0DbqFGVSMx`Z_pw9kVYjHaiWkTa^@~14k2z71IB8tm(si%vjWq*LbQf z-d1=ro5n6|Y^O8;L>-%p*1DO8U;Q4Fy`-K9YH3Q%-X~LHZfJ&C#BW*R%@Xmou5U*1 zv^^_BfBrU1P4lw}9Ce&L<}l$36h+hY5%w99f0l`Uu3oMgm}Z8C{QlQMClKp*@3H(h zN4pqOBYX4&>AuSxK%jc0U~zK_l%@>k+zA#jeDD1J(4C%oy0|ib1v+(D1yFvWgtp&tIO!M;~QA05qvP_j5O52l5)T^&6vbfN1sepIEwF;}Q&}@Lk&E_X)H{s($LT z?cMD@JpHDBHVA`nCOlb_BvFMcV5NqUN8m5JB)j6jlKju~>f<^=6X8|hUi zqZNHL_yg3fxXOcWSaGnEsZ7sJ0cH!USaQYKvIFEKI_S@V$8=p}14j?@{g=Wj?Kd!j z1%?a_cHBA?8D(Gjtc!!VNJns~k5hK(GGj?S`LEU52CpDf(b%_==c_y?#3r*v{-P@d zza;yu38nbpTOX^VtV0?YSSad@z)Xs4l>W1>2rCcAjjHWME0He_@xO~hn*I`fH(Gh( z#r_ZwzJ;w_P(g;c?uzS`8=G4}hpeBD8_k7TA&%*D(DI44+^MTjPhxofSXmsu)hEpB zK%y{l)^%|^a@QG&Z5;7#Z!-xtL9^AyQ{3j6aP&Ys=zKcAq+nC*hyz*3mQ?A!7!T=6%8pm=A@+{M||9g@!`y~fQ!rJnk9@Xmv85@y2S+1@(T$T3x}l>y&rSc4OhD8 z*g*El4^wd@3#Vu=;3{3grtpyuop(I>It@(2vLg1h5rs>7nU;JfTw;bUr}QB8#H%Ta z`i;|*?|n`LL^}~(!EwvsdmS#{ZGva%)RM@w8*~Pu>( literal 0 HcmV?d00001 diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/87d2ac0c-0.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/87d2ac0c-0.avif deleted file mode 100644 index 7a180dca5132d8b22c51cf41e0d4d031c284aaf4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6432 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 diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/92dc20a7-0.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/92dc20a7-0.avif deleted file mode 100644 index 3331e1f5616c6b3a121d48376264f536fd25f22d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14531 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 Tt|W~r;3v|@2XCJsS^ob60Eg!r diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/a3eefe73-0.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/a3eefe73-0.avif deleted file mode 100644 index 3c6fc0e54a64213e7dbae924b77cd96df9f60b6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8158 zcmYLuRa6{G)9v68Ah-u7=-`l`!3hKl4uKFH26uON5AF`Z-Q6v?JA?r;Gq~H&Ip==s z)c?&X0PxP#$=%Mt1!M|%jepP@WXfp`GI-^1cGf0N2LI@p58v8>oUH#PaIY&5$ja8}A0{aZfCv1e0N|4TLjZsR>s5OV%7XtX0Kr$v z2LjprdyIcwf>&blZ`o_NfeQ!cKOO&He0BaOR)g#u>|V_Xke!k3D`FV9a7y?iV*Jy9 z4|23K`6mGY;G|i5c zZD(Tk?;1TwM{aCCQcGO>0Pc&!0hfeakn1q`h0%>TVFa*&<%zsYOs>+}fz@CX2S z#2|R2kXL~em_fynp$PJ#+mBpWs1o950{L^nKnB@q+R3_ox1iNbW6 zN*HUDizl&}tfA51ZLCN=IjX@)gJBrko^uoLcBs&aqRRWm`NBTkgUb}>;4>v7*HMZg zHIzOSXW6@TeAgy0f@5C0ui_E!%UB}rST@b0hV_Kf&`!~uH+mVPW%I(KMe5|L+Ggk_ z0hwuYr++e8HP)TY=}tg_2-(NCby0WvY-s}{4~JxxbAipR>b2=M0^_ON4+e(T6XC{J zCp$AW0JNa1AW=6R7gj=!>(hov(lYW6WiQwJ#q=Ug;Qk^&(Hbv4pvJ3kXwlG31aewR zL7<456$=>dUP7JEtka?ZNf~b=#rB3LDHxw5efmb%5fs174;)G=%F^ys(&uX|5lE1speFKrm5V zQWm(S!9^g-T1tywa~5>uNl2ujOkKm68q`sM4~9+m{j82#flJM2NjzB;mz$5iJg{yR zguoFT=E~>j>m3lzXDFXGx!^5Wjb4bQK`IWlLivoyez-L5mo~w6?t&LgONr)XGi1;0?EZ*%z?ssmv~Eb}FLP1m(L+{G%hl_fdFuyjc+ymg#!W*+iy3+}$FPJC;I5j(^eMwY5=3Xk@$z3&{8BMJn2mEn zw?Owbt3aOHFQPei&5q6Ts&j~9ca=NWChIobyS8qiguU_ShDE4MPj$f-mKN|b%zAW` z&9EB9%+_X_#svfpAw;RK(aB8SP{yjd46D*9&nS=om!cMv={whzSo!{|dUK#| zQI*gk{sr4lLY6acDQOwR!f>>n-wzxqyH2}yGM-it-k@KH?{)O^(odwm zr5*XsGPljBJz4J^x{{weJ7F!J|Kb~PF-~?I2yG#oCje_A`}=FggfB3)H)a(u2LMlT zdnnvt%KcW}-P?p!W0aE+;#t)d z@rTd9CNnXI6!|Wbf^HWT2WtKRG}8k6(FMm!`ZI8zDWd50n2)KDp(MH<;bq3lr=P

ptAaBE$}cN(x|^r!J%*H0mP?5+DzJ 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 n8z@B{Use1XF5;qc9ol(GmU70000u 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 literal 0 HcmV?d00001 diff --git a/public/docs/images/tutorials/multi-product-formula/extracted-outputs/d751af7c-0.avif b/public/docs/images/tutorials/multi-product-formula/extracted-outputs/d751af7c-0.avif deleted file mode 100644 index 8364ca7036ac7b8f5c1efc8e5f8693f9276a34f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8990 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 Date: Tue, 26 May 2026 17:32:06 -0400 Subject: [PATCH 02/21] Fixed link --- docs/tutorials/multi-product-formula.ipynb | 25 ++++++++-------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index f24419e01ba..654d49fa736 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -10,7 +10,7 @@ "description: Use multi-product formulas in observable estimation to reduce Trotter error or implement time-evolution with fixed Trotter error in lower depth.\n", "---\n", "\n", - "{/* cspell:ignore ncol circo Layerwise markersize unbiasedness infty ndash lesssim propto tenpy unfused N\u00e9el correlator Neel exponentiating gtrsim */}\n", + "{/* cspell:ignore ncol circo Layerwise markersize unbiasedness infty ndash lesssim propto tenpy unfused Néel correlator Neel exponentiating gtrsim */}\n", "\n", "# Multi-product formulas to reduce Trotter error\n", "*Usage estimate: Four minutes on a Heron r2 processor (NOTE: This is an estimate only. Your runtime may vary.)*" @@ -74,7 +74,7 @@ "\\langle A \\rangle_{\\text{MPF}}(t) = \\sum_{j=1}^r x_j \\, \\langle A \\rangle_{k_j}(t),\n", "$$\n", "\n", - "where $\\langle A \\rangle_{k_j}(t)$ is the expectation value of an observable $A$ at time $t$ estimated from a Trotter circuit with $k_j$ steps, and the coefficients $\\{x_j\\}_{j=1}^r$ are chosen so that the leading Trotter-error terms in the combination cancel. We will revisit this expression in [Step 4](#step-4-post-process-and-return-result-in-desired-classical-format), where we evaluate it explicitly to combine our Trotter results. The key practical point is that the deepest circuit in the MPF only needs $k_{\\max}$ steps, which is much smaller than the single $k$ that would be required to reach the same effective Trotter error directly. The shallower circuits make the MPF approach better suited to noisy hardware.\n", + "where $\\langle A \\rangle_{k_j}(t)$ is the expectation value of an observable $A$ at time $t$ estimated from a Trotter circuit with $k_j$ steps, and the coefficients $\\{x_j\\}_{j=1}^r$ are chosen so that the leading Trotter-error terms in the combination cancel. We will revisit this expression in [Step 4](#small-scale-step-4), where we evaluate it explicitly to combine our Trotter results. The key practical point is that the deepest circuit in the MPF only needs $k_{\\max}$ steps, which is much smaller than the single $k$ that would be required to reach the same effective Trotter error directly. The shallower circuits make the MPF approach better suited to noisy hardware.\n", "\n", "### How are the coefficients determined?\n", "\n", @@ -245,7 +245,7 @@ "source": [ "### Step 1: Map classical inputs to a quantum problem\n", "\n", - "We begin with a 10-qubit Heisenberg model on a line, using the N\u00e9el state $\\vert 0101\\ldots01 \\rangle$ as the initial state. The Hamiltonian is:\n", + "We begin with a 10-qubit Heisenberg model on a line, using the Néel state $\\vert 0101\\ldots01 \\rangle$ as the initial state. The Hamiltonian is:\n", "\n", "$$\n", "\\hat{\\mathcal{H}}_{\\text{Heis}} = J \\sum_{i=1}^{L-1} \\left(X_i X_{i+1} + Y_i Y_{i+1} + Z_i Z_{i+1}\\right),\n", @@ -451,6 +451,7 @@ "id": "a384f017", "metadata": {}, "source": [ + "\n", "### Step 4: Post-process and return result in desired classical format\n", "\n", "Step 4 is where the MPF is actually constructed. Even though the coefficients $x_j$ are *computed* here (and, for the dynamic variant, this computation can be intensive), conceptually they are a classical recipe for combining the quantum measurements from Step 3 into a single corrected expectation value — so we treat the whole coefficient + combination workflow as post-processing.\n", @@ -809,7 +810,7 @@ "id": "2486594c", "metadata": {}, "source": [ - "Finally, we define an `identity_factory` that yields the initial MPO state and prepare the N\u00e9el initial state as an MPS that matches the lattice used by the layered Trotter model." + "Finally, we define an `identity_factory` that yields the initial MPO state and prepare the Néel initial state as an MPS that matches the lattice used by the layered Trotter model." ] }, { @@ -1634,9 +1635,9 @@ "\n", "\n", "If you found this work interesting, you might be interested in the following material:\n", - "- [How to choose the Trotter steps for an MPF](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) \u2014 practical guidance on selecting $k_j$ values to avoid instabilities\n", - "- [How to use the approximate model](https://qiskit.github.io/qiskit-addon-mpf/how_tos/using_approximate_model.html) \u2014 tuning the $L_1$-norm constraint and solver options for the approximate static MPF\n", - "- [qiskit-addon-mpf API reference](https://qiskit.github.io/qiskit-addon-mpf/) \u2014 full documentation for static, dynamic, and backend modules\n", + "- [How to choose the Trotter steps for an MPF](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) — practical guidance on selecting $k_j$ values to avoid instabilities\n", + "- [How to use the approximate model](https://qiskit.github.io/qiskit-addon-mpf/how_tos/using_approximate_model.html) — tuning the $L_1$-norm constraint and solver options for the approximate static MPF\n", + "- [qiskit-addon-mpf API reference](https://qiskit.github.io/qiskit-addon-mpf/) — full documentation for static, dynamic, and backend modules\n", "" ] }, @@ -1653,14 +1654,6 @@ "\n", "\\[3] Robertson, N. F., et al. Tensor network enhanced dynamic multiproduct formulas. [arXiv:2407.17405 (2024)](https://arxiv.org/abs/2407.17405)" ] - }, - { - "cell_type": "markdown", - "id": "e47f668a", - "metadata": {}, - "source": [ - "\u00a9 IBM Corp., 2026" - ] } ], "metadata": { @@ -1684,4 +1677,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} From 842d6901fe656a77b8aac578c6a360123f5894ec Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:15:21 -0400 Subject: [PATCH 03/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 654d49fa736..aa303fc0065 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -26,7 +26,7 @@ "- How multi-product formulas (MPFs) reduce Trotter error in Hamiltonian simulation by combining expectation values from multiple shallow circuits\n", "- When MPFs are beneficial over standard product formulas and when they are not the right tool\n", "- How to compute static and dynamic MPF coefficients using the `qiskit_addon_mpf` package\n", - "- How to execute an MPF workflow end-to-end on IBM Quantum hardware, including transpilation, error mitigation, and post-processing" + "- How to execute an MPF workflow end-to-end on IBM Quantum® hardware, including transpilation, error mitigation, and post-processing" ] }, { From c35786e3b41d1d6b0d98c5439991c8d7609a64bc Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:15:32 -0400 Subject: [PATCH 04/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index aa303fc0065..cd5d07a8679 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -86,7 +86,7 @@ "\\sum_{j=1}^r x_j = 1, \\quad \\sum_{j=1}^r \\frac{x_j}{k_j^{\\eta_n}} = 0 \\quad (n = 0, \\ldots, r-2),\n", "$$\n", "\n", - "where the integer exponents $\\{\\eta_n\\}$ are the orders of the successive Trotter-error terms for the chosen product formula. For a *symmetric* $2\\chi$-order PF, the leading error in $\\left[S_{2\\chi}(t/k)\\right]^k$ scales as $1/k^{2\\chi}$, with subsequent corrections at $1/k^{2\\chi+2}, 1/k^{2\\chi+4}, \\ldots$ — so the exponents are $\\eta_n = 2\\chi + 2n$. For non-symmetric PFs, both odd and even powers contribute and $\\eta_n = 2\\chi + n$. See Ref. [\\[1\\]](#references) for the full derivation. The first equation in the system above ensures unbiasedness (the MPF reproduces the exact expectation value in the $k_j \\to \\infty$ limit), and the remaining $r-1$ equations successively cancel the first $r-1$ Trotter-error terms. When the resulting $L_1$-norm $\\|x\\|_1$ is too large (which amplifies sampling noise), one can instead solve an approximate optimization that caps $\\|x\\|_1$ while minimizing $\\|Ax - b\\|$.\n", + "where the integer exponents $\\{\\eta_n\\}$ are the orders of the successive Trotter-error terms for the chosen product formula. For a *symmetric* $2\\chi$-order PF, the leading error in $\\left[S_{2\\chi}(t/k)\\right]^k$ scales as $1/k^{2\\chi}$, with subsequent corrections at $1/k^{2\\chi+2}, 1/k^{2\\chi+4}, \\ldots$ — so the exponents are $\\eta_n = 2\\chi + 2n$. For non-symmetric PFs, both odd and even powers contribute and $\\eta_n = 2\\chi + n$. See Ref. [\\[1\\]](#references) for the full derivation. The first equation in the system above ensures unbiasedness (the MPF reproduces the exact expectation value in the $k_j \\to \\infty$ limit), and the remaining $r-1$ equations successively cancel the first $r-1$ Trotter-error terms. When the resulting $L_1$-norm $\\|x\\|_1$ is too large (which amplifies sampling noise), you can instead solve an approximate optimization that caps $\\|x\\|_1$ while minimizing $\\|Ax - b\\|$.\n", "\n", "**Dynamic coefficients** [\\[2\\]](#references), [\\[3\\]](#references) additionally depend on the Hamiltonian, initial state, and evolution time $t$. They minimize the Frobenius-norm distance between the true time-evolved state and the MPF approximation:\n", "\n", From 6de5fac941ebc780359054291540e3759876a9f1 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:15:45 -0400 Subject: [PATCH 05/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index cd5d07a8679..f4eec81ebfd 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -100,8 +100,8 @@ "\n", "MPFs are most beneficial when:\n", "\n", - "- **Circuit depth is the bottleneck.** If hardware noise limits the depth you can run, MPFs let you achieve higher effective Trotter accuracy from shallower circuits.\n", - "- **You need accurate expectation values, not full state preparation.** MPFs operate at the level of expectation values — they combine classical numbers, not quantum states. This makes them ideal for observable estimation via the Estimator primitive.\n", + "- **Circuit depth is the bottleneck.** If hardware noise limits the depth you can run, use MPFs to achieve higher effective Trotter accuracy from shallower circuits.\n", + "- **You need accurate expectation values, not full state preparation.** MPFs operate at the level of expectation values — they combine classical numbers, not quantum states. They are therefore ideal for observable estimation when using the Estimator primitive.\n", "- **You combine a modest number of Trotter-step counts.** Typically combining $r = 3$–$5$ different step counts $k_j$ is sufficient to cancel several leading Trotter-error terms while keeping $\\|x\\|_1$ manageable.\n", "\n", "### When MPFs may not help\n", From 884dc381357b4e0996c280f6ae3723d9ff58691b Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:16:10 -0400 Subject: [PATCH 06/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index f4eec81ebfd..bc7482abe47 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -107,7 +107,7 @@ "### When MPFs may not help\n", "\n", "- **Very short evolution times.** When $t$ is small enough that a single low-order Trotter formula is already accurate, the overhead of running multiple circuits is unnecessary.\n", - "- **State-preparation tasks.** MPFs produce a corrected *expectation value*, not a corrected quantum state. If you need the actual time-evolved state (e.g., as input to another quantum subroutine), MPFs do not apply.\n", + "- **State-preparation tasks.** MPFs produce a corrected *expectation value*, not a corrected quantum state. If you need the actual time-evolved state (for example, as input to another quantum subroutine), MPFs do not apply.\n", "- **Trotter-step counts that violate the convergence regime.** The static-coefficient derivation expands each individual $\\left[S_{2\\chi}(t/k_j)\\right]^{k_j}$ as a series in $t/k_j$; this expansion only converges well when $t/k_{\\min} \\lesssim 1$. If $k_{\\min}$ is chosen too small for the given $t$, the shallowest circuit is far outside the perturbative regime, the higher-order error terms that the MPF leaves uncanceled become large, and the cancellation can require large coefficients. The $L_1$-norm $\\|x\\|_1$ is the practical diagnostic: when $\\|x\\|_1 \\gg 1$, the sampling overhead $\\propto \\|x\\|_1^2$ may outweigh the Trotter-error reduction. See the [guide on choosing Trotter steps](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) for details.\n", "\n", "### What this tutorial covers\n", From addc24f1991fb08c75124f182f4b4d7488e2c621 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:16:24 -0400 Subject: [PATCH 07/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index bc7482abe47..55835da4134 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -104,7 +104,7 @@ "- **You need accurate expectation values, not full state preparation.** MPFs operate at the level of expectation values — they combine classical numbers, not quantum states. They are therefore ideal for observable estimation when using the Estimator primitive.\n", "- **You combine a modest number of Trotter-step counts.** Typically combining $r = 3$–$5$ different step counts $k_j$ is sufficient to cancel several leading Trotter-error terms while keeping $\\|x\\|_1$ manageable.\n", "\n", - "### When MPFs may not help\n", + "### When MPFs might not help\n", "\n", "- **Very short evolution times.** When $t$ is small enough that a single low-order Trotter formula is already accurate, the overhead of running multiple circuits is unnecessary.\n", "- **State-preparation tasks.** MPFs produce a corrected *expectation value*, not a corrected quantum state. If you need the actual time-evolved state (for example, as input to another quantum subroutine), MPFs do not apply.\n", From a6d0d7941bba3650c8fef87fb0dfdc6bc546e9a9 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:17:03 -0400 Subject: [PATCH 08/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 55835da4134..8eaf75f0c9c 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -108,7 +108,7 @@ "\n", "- **Very short evolution times.** When $t$ is small enough that a single low-order Trotter formula is already accurate, the overhead of running multiple circuits is unnecessary.\n", "- **State-preparation tasks.** MPFs produce a corrected *expectation value*, not a corrected quantum state. If you need the actual time-evolved state (for example, as input to another quantum subroutine), MPFs do not apply.\n", - "- **Trotter-step counts that violate the convergence regime.** The static-coefficient derivation expands each individual $\\left[S_{2\\chi}(t/k_j)\\right]^{k_j}$ as a series in $t/k_j$; this expansion only converges well when $t/k_{\\min} \\lesssim 1$. If $k_{\\min}$ is chosen too small for the given $t$, the shallowest circuit is far outside the perturbative regime, the higher-order error terms that the MPF leaves uncanceled become large, and the cancellation can require large coefficients. The $L_1$-norm $\\|x\\|_1$ is the practical diagnostic: when $\\|x\\|_1 \\gg 1$, the sampling overhead $\\propto \\|x\\|_1^2$ may outweigh the Trotter-error reduction. See the [guide on choosing Trotter steps](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) for details.\n", + "- **Trotter-step counts that violate the convergence regime.** The static-coefficient derivation expands each individual $\\left[S_{2\\chi}(t/k_j)\\right]^{k_j}$ as a series in $t/k_j$; this expansion only converges well when $t/k_{\\min} \\lesssim 1$. If $k_{\\min}$ is chosen too small for the given $t$, the shallowest circuit is far outside the perturbative regime, the higher-order error terms that the MPF leaves uncanceled become large, and the cancellation can require large coefficients. The $L_1$-norm $\\|x\\|_1$ is the practical diagnostic: when $\\|x\\|_1 \\gg 1$, the sampling overhead $\\propto \\|x\\|_1^2$ might outweigh the Trotter-error reduction. See the [guide on choosing Trotter steps](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) for details.\n", "\n", "### What this tutorial covers\n", "\n", From a64d369fe5646cb1047508429ee5512fa8d1f08b Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:17:17 -0400 Subject: [PATCH 09/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 8eaf75f0c9c..6ed5c73cf2d 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -331,7 +331,7 @@ "source": [ "#### Build Trotter circuits\n", "\n", - "We create the circuits implementing the approximate Trotter time-evolutions for each time point and each Trotter step count. The `CollectAndCollapse` pass defined in Setup collects XX and YY rotations into single XX+YY gates, enabling more efficient tensor-network simulation later." + "We create the circuits implementing the approximate Trotter time-evolutions for each time point and each Trotter step count. The `CollectAndCollapse` pass defined in the Setup section collects XX and YY rotations into single XX+YY gates, to prepare for more efficient tensor-network simulation later." ] }, { From ddfd04af9b9ad60c6d0ad9ca1a2256eca40c6547 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:17:28 -0400 Subject: [PATCH 10/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 6ed5c73cf2d..07eb1351d47 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -506,7 +506,7 @@ "\\end{bmatrix}.\n", "$$\n", "\n", - "The first row enforces unbiasedness ($\\sum_j x_j = 1$); the second and third rows cancel the leading $1/k^2$ and next-order $1/k^3$ Trotter-error terms respectively." + "The first row enforces unbiasedness ($\\sum_j x_j = 1$); the second and third rows cancel the leading $1/k^2$ and next-order $1/k^3$ Trotter-error terms, respectively." ] }, { From c5745faed18de3bb0ec851b62db2d8f0783c0014 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:17:41 -0400 Subject: [PATCH 11/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 07eb1351d47..eac18d694c4 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -454,7 +454,7 @@ "\n", "### Step 4: Post-process and return result in desired classical format\n", "\n", - "Step 4 is where the MPF is actually constructed. Even though the coefficients $x_j$ are *computed* here (and, for the dynamic variant, this computation can be intensive), conceptually they are a classical recipe for combining the quantum measurements from Step 3 into a single corrected expectation value — so we treat the whole coefficient + combination workflow as post-processing.\n", + "Step 4 is where the MPF is actually constructed. Even though the coefficients $x_j$ are *computed* here (and, for the dynamic variant, this computation can be intensive), conceptually they are a classical recipe for combining the quantum measurements from Step 3 into a single corrected expectation value — so we treat the whole coefficient and combination workflow as post-processing.\n", "\n", "To assess how well the MPF tracks the true dynamics, we first compute the exact time-evolved expectation values by directly exponentiating the Hamiltonian. This is only tractable because $L = 10$; in the large-scale hardware example below we will have to rely on tensor-network estimates instead." ] From 1a633f5d0d34d552b1407de61198faf087b952f8 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:17:58 -0400 Subject: [PATCH 12/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index eac18d694c4..81331e305a2 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -516,7 +516,7 @@ "source": [ "##### Set up the LSE\n", "\n", - "We use `setup_static_lse` from `qiskit_addon_mpf.static` to assemble the matrix $A$ and right-hand-side vector $b$ described above. The matrix $A$ depends not only on $k_j$ but also on our choice of product formula — in particular its *order* $\\chi$ and whether it is *symmetric*. The `symmetric` flag controls the exponent pattern $\\eta_n$ (symmetric formulas only produce even-power Trotter-error terms; see Ref. [\\[1\\]](#references)). Note that, as shown in Ref. [\\[2\\]](#references), setting `symmetric=True` is not strictly necessary even when the underlying PF is symmetric — the non-symmetric LSE remains valid (it just enforces extra unneeded constraints).\n", + "We use `setup_static_lse` from `qiskit_addon_mpf.static` to assemble the matrix $A$ and right-hand-side vector $b$ described above. The matrix $A$ depends not only on $k_j$ but also on our choice of product formula — in particular its *order* $\\chi$ and whether it is *symmetric*. The `symmetric` flag controls the exponent pattern $\\eta_n$ (symmetric formulas only produce even-power Trotter-error terms; see Ref. [\\[1\\]](#references)). Note that, as shown in Ref. [\\[2\\]](#references), setting `symmetric=True` is not strictly necessary even when the underlying PF is symmetric — the non-symmetric LSE remains valid (it enforces extra unneeded constraints).\n", "\n", "For our example we already set `order = 2` and `symmetric = False` in Step 1." ] From 1bb58af2f5287e3e5e16e08f8ec38049f64089f8 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:18:34 -0400 Subject: [PATCH 13/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 81331e305a2..15a9de77a5e 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1048,7 +1048,7 @@ "\n", "- **Trotter error.** The individual product formulas (grey markers) deviate from the exact curve more and more as time grows, with the largest deviation for $k=1$ — that circuit is the shallowest, but it is also already in the regime where $t/k \\gtrsim 1$, so the leading $1/k^{2}$ error term is large. The MPF combinations (colored markers) cancel several of these leading Trotter-error terms, so they track the exact curve much more closely than any single $k_j$ circuit. The remaining gap reflects the higher-order Trotter terms that the MPF does *not* cancel: an order-$2$, $r=3$ static MPF only kills the first two error orders, and at large $t/k_{\\min}$ the uncancelled tail eventually dominates — so MPF is not a free pass to use very shallow circuits at arbitrary times.\n", "\n", - "- **Sampling error.** The wider error bars on the MPF curves are a direct consequence of the linear combination: propagating independent per-circuit standard errors $\\sigma_{k_j}$ gives a total variance $\\sigma_{\\text{MPF}}^2 = \\sum_j x_j^2 \\, \\sigma_{k_j}^2$. So the larger the $\\|x\\|_2$ (and in practice the $\\|x\\|_1$, which is what we control), the more shots are required to reach a given target uncertainty. This is the trade-off behind the approximate-solver option in the Background: we cap $\\|x\\|_1$ to keep this overhead manageable. Crucially, unlike Trotter error, sampling error shrinks with $1/\\sqrt{N_{\\text{shots}}}$, so it can always be reduced by spending more shots.\n", + "- **Sampling error.** The wider error bars on the MPF curves are a direct consequence of the linear combination: propagating independent per-circuit standard errors $\\sigma_{k_j}$ gives a total variance $\\sigma_{\\text{MPF}}^2 = \\sum_j x_j^2 \\, \\sigma_{k_j}^2$. Therefore, the larger the $\\|x\\|_2$ (and in practice the $\\|x\\|_1$, which is what we control), the more shots are required to reach a given target uncertainty. This is the trade-off behind the approximate-solver option in the Background: we cap $\\|x\\|_1$ to keep this overhead manageable. Crucially, unlike Trotter error, sampling error shrinks with $1/\\sqrt{N_{\\text{shots}}}$, so it can always be reduced by spending more shots.\n", "\n", "In the large-scale hardware example below, hardware noise enters as an additional error source on each $\\langle A \\rangle_{k_j}$, which similarly gets amplified by the MPF coefficients. We will see how error mitigation interacts with MPFs in that section." ] From 5bb3e4d6d99563d4f498ce97cc564173a5d92cb7 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:18:54 -0400 Subject: [PATCH 14/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 15a9de77a5e..c63db31f2ff 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1060,7 +1060,7 @@ "source": [ "## Large-scale hardware example\n", "\n", - "Let's scale the problem up beyond what is possible to simulate exactly. In this section we reproduce some of the results shown in Ref. [\\[3\\]](#references), using a 50-qubit XXZ chain at time $t = 3$. We use the same four-step workflow as above, but pull out the hardware-specific details (qubit filtering, transpilation, and error mitigation) into their own subsections after Step 1." + "In this section we scale the problem up beyond what is possible to simulate exactly. We reproduce some of the results shown in Ref. [\\[3\\]](#references), using a 50-qubit XXZ chain at time $t = 3$. We use the same four-step workflow as above, but pull out the hardware-specific details (qubit filtering, transpilation, and error mitigation) into their own subsections after Step 1." ] }, { From 0bf637e7a2d727d3ac84ac1b84d56ea389b68866 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:19:05 -0400 Subject: [PATCH 15/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index c63db31f2ff..fb85784c128 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1637,7 +1637,7 @@ "If you found this work interesting, you might be interested in the following material:\n", "- [How to choose the Trotter steps for an MPF](https://qiskit.github.io/qiskit-addon-mpf/how_tos/choose_trotter_steps.html) — practical guidance on selecting $k_j$ values to avoid instabilities\n", "- [How to use the approximate model](https://qiskit.github.io/qiskit-addon-mpf/how_tos/using_approximate_model.html) — tuning the $L_1$-norm constraint and solver options for the approximate static MPF\n", - "- [qiskit-addon-mpf API reference](https://qiskit.github.io/qiskit-addon-mpf/) — full documentation for static, dynamic, and backend modules\n", + "- [`qiskit-addon-mpf` API reference](https://qiskit.github.io/qiskit-addon-mpf/) — full documentation for static, dynamic, and backend modules\n", "" ] }, From 93d4dc32cf7b78d8e6cbb828124609a2f357b8eb Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:19:17 -0400 Subject: [PATCH 16/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index fb85784c128..654da7cb59b 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1623,7 +1623,7 @@ "\n", "- **The chosen Trotter steps are partly outside the safe regime.** At $t = 3$ with $k_{\\min} = 2$, the ratio $t/k_{\\min} = 1.5 > 1$, which is past the convergence threshold discussed in the Background. The leading-error cancellation the static MPF relies on is therefore less effective, and the dynamic MPF's tensor-network reference for the \"exact\" state is also strained — even so, the dynamic MPF performs well here because its coefficients adapt to whatever errors the approximate evolver does see.\n", "\n", - "The practical takeaway is that on hardware, MPFs should be paired with strong error mitigation on each individual $\\langle A \\rangle_{k_j}$, the coefficient $L_1$-norm should be kept modest (use the approximate solver, or prefer the dynamic MPF when its tensor-network setup is tractable), and the Trotter steps $k_j$ should be chosen so that $t/k_{\\min} \\lesssim 1$. With those choices, as we see here for the dynamic MPF, the MPF can recover the depth-vs-accuracy advantage shown in Ref. [\\[3\\]](#references). Note also that individual runs are noisy — on a different submission of the same job (or a different backend), the relative ordering of these estimators can shift; the qualitative trend that small-$\\|x\\|_1$ MPFs do well and large-$\\|x\\|_1$ MPFs are amplified by hardware noise is the robust one." + "The practical takeaway is that on hardware, MPFs should be paired with strong error mitigation on each individual $\\langle A \\rangle_{k_j}$, the coefficient $L_1$-norm should be kept modest (use the approximate solver, or prefer the dynamic MPF when its tensor-network setup is tractable), and the Trotter steps $k_j$ should be chosen so that $t/k_{\\min} \\lesssim 1$. With those choices, as we see here for the dynamic MPF, the MPF can recover the depth-versus-accuracy advantage shown in Ref. [\\[3\\]](#references). Note also that individual runs are noisy — on a different submission of the same job (or a different backend), the relative ordering of these estimators can shift; the qualitative trend that small-$\\|x\\|_1$ MPFs do well and large-$\\|x\\|_1$ MPFs are amplified by hardware noise is the robust one." ] }, { From 2e7fb825571fa5811c9955837bfbe4d6f22cbe05 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:19:28 -0400 Subject: [PATCH 17/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 654da7cb59b..bcfaa5c446a 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1617,7 +1617,7 @@ "\n", "- **Coefficient norm matters more than mathematical optimality.** The exact-static MPF has $\\|x\\|_1 = 5.63$, and its final estimate ends up far from the true value — that large coefficient norm amplifies the residual gate noise, decoherence, and ZNE error on each $\\langle A \\rangle_{k_j}$ by roughly the same factor, swamping the Trotter-error cancellation we gained. The approximate-static MPF (capped at $\\|x\\|_1 = 2$) and the dynamic MPF (whose coefficients here are similarly modest in magnitude) avoid this blow-up and land much closer to the reference.\n", "\n", - "- **The dynamic MPF is the best estimator in this run.** Tailoring the coefficients to this specific Hamiltonian, initial state, and time gives an answer closer to the exact reference than any single Trotter circuit — including the deeper $k = 6$ baseline — and substantially closer than either static MPF. This is the regime MPFs are designed for: shallow constituent circuits combined with well-chosen, small-norm coefficients.\n", + "- **The dynamic MPF is the best estimator in this run.** Tailoring the coefficients to this specific Hamiltonian, initial state, and time gives an answer closer to the exact reference than any single Trotter circuit — including the deeper $k = 6$ baseline — and is substantially closer than either static MPF. This is the regime MPFs are designed for: shallow constituent circuits combined with well-chosen, small-norm coefficients.\n", "\n", "- **Individual product formulas are still competitive on hardware.** Note that the single-circuit baselines ($k = 2, 3, 6$) all sit within roughly $0.1$ of the exact reference, while the static-exact MPF is off by more than $0.5$. This is the failure mode the small-scale Background discussion warned about: an MPF that mathematically cancels Trotter error can be *worse* than a single product formula once hardware noise is amplified by $\\|x\\|_1$.\n", "\n", From 288f570fa302e668ad36020ab836181df61acec0 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:19:38 -0400 Subject: [PATCH 18/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index bcfaa5c446a..f9ec9d6e9de 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1077,7 +1077,7 @@ "- A single fixed evolution time $t = 3$.\n", "- An additional **single-circuit comparison run with $k = 6$ Trotter steps**, used as a baseline. We chose $k = 6$ because its two-qubit depth on hardware is comparable to the deepest MPF constituent ($k_{\\max}=4$) plus the overhead of running multiple MPF circuits — so $k=6$ is a fair \"single deep circuit\" comparison against the MPF combination, not a circuit that targets the MPF's effective Trotter error (which would require many more steps).\n", "\n", - "Note that even though we are still in Step 1 here (mapping + circuit construction), we also pre-compute the dynamic coefficients alongside the static ones in this cell. Dynamic coefficients depend on $H$ and $t$ but not on the quantum measurements, so they can be computed any time before Step 4. We do it now to keep all the MPF-specific setup in one place." + "Note that even though we are still in Step 1 here (mapping and circuit construction), we also pre-compute the dynamic coefficients alongside the static ones in this cell. Dynamic coefficients depend on $H$ and $t$ but not on the quantum measurements, so they can be computed any time before Step 4. We do it now to keep all the MPF-specific setup in one place." ] }, { From d53dbb3cd9030c1a62587ef68c70fa7479314f36 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:19:54 -0400 Subject: [PATCH 19/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index f9ec9d6e9de..4601706ddcb 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1615,7 +1615,7 @@ "source": [ "A few observations about the hardware results above:\n", "\n", - "- **Coefficient norm matters more than mathematical optimality.** The exact-static MPF has $\\|x\\|_1 = 5.63$, and its final estimate ends up far from the true value — that large coefficient norm amplifies the residual gate noise, decoherence, and ZNE error on each $\\langle A \\rangle_{k_j}$ by roughly the same factor, swamping the Trotter-error cancellation we gained. The approximate-static MPF (capped at $\\|x\\|_1 = 2$) and the dynamic MPF (whose coefficients here are similarly modest in magnitude) avoid this blow-up and land much closer to the reference.\n", + "- **Coefficient norm matters more than mathematical optimality.** The exact-static MPF has $\\|x\\|_1 = 5.63$, and its final estimate ends up far from the true value — the large coefficient norm amplifies the residual gate noise, decoherence, and ZNE error on each $\\langle A \\rangle_{k_j}$ by roughly the same factor, overwhelming the Trotter-error cancellation we gained. The approximate-static MPF (capped at $\\|x\\|_1 = 2$) and the dynamic MPF (whose coefficients here are similarly modest in magnitude) avoid this overwhelm and land much closer to the reference.\n", "\n", "- **The dynamic MPF is the best estimator in this run.** Tailoring the coefficients to this specific Hamiltonian, initial state, and time gives an answer closer to the exact reference than any single Trotter circuit — including the deeper $k = 6$ baseline — and is substantially closer than either static MPF. This is the regime MPFs are designed for: shallow constituent circuits combined with well-chosen, small-norm coefficients.\n", "\n", From 879b7dae6d51ccdadd2063bb2f770df710624867 Mon Sep 17 00:00:00 2001 From: Henry Zou <87874865+henryzou50@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:20:04 -0400 Subject: [PATCH 20/21] Update docs/tutorials/multi-product-formula.ipynb Co-authored-by: abbycross --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 4601706ddcb..5929a5614cc 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -518,7 +518,7 @@ "\n", "We use `setup_static_lse` from `qiskit_addon_mpf.static` to assemble the matrix $A$ and right-hand-side vector $b$ described above. The matrix $A$ depends not only on $k_j$ but also on our choice of product formula — in particular its *order* $\\chi$ and whether it is *symmetric*. The `symmetric` flag controls the exponent pattern $\\eta_n$ (symmetric formulas only produce even-power Trotter-error terms; see Ref. [\\[1\\]](#references)). Note that, as shown in Ref. [\\[2\\]](#references), setting `symmetric=True` is not strictly necessary even when the underlying PF is symmetric — the non-symmetric LSE remains valid (it enforces extra unneeded constraints).\n", "\n", - "For our example we already set `order = 2` and `symmetric = False` in Step 1." + "For our example we have already set `order = 2` and `symmetric = False` in Step 1." ] }, { From b8cc1dc7997a6e46daf4fc89e813efaf531c4fc3 Mon Sep 17 00:00:00 2001 From: Henry Zou Date: Tue, 2 Jun 2026 14:30:57 -0400 Subject: [PATCH 21/21] Test revision --- docs/tutorials/multi-product-formula.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/multi-product-formula.ipynb b/docs/tutorials/multi-product-formula.ipynb index 5929a5614cc..97595a2f800 100644 --- a/docs/tutorials/multi-product-formula.ipynb +++ b/docs/tutorials/multi-product-formula.ipynb @@ -1046,7 +1046,7 @@ "source": [ "The plot above illustrates the interplay between Trotter error and sampling error.\n", "\n", - "- **Trotter error.** The individual product formulas (grey markers) deviate from the exact curve more and more as time grows, with the largest deviation for $k=1$ — that circuit is the shallowest, but it is also already in the regime where $t/k \\gtrsim 1$, so the leading $1/k^{2}$ error term is large. The MPF combinations (colored markers) cancel several of these leading Trotter-error terms, so they track the exact curve much more closely than any single $k_j$ circuit. The remaining gap reflects the higher-order Trotter terms that the MPF does *not* cancel: an order-$2$, $r=3$ static MPF only kills the first two error orders, and at large $t/k_{\\min}$ the uncancelled tail eventually dominates — so MPF is not a free pass to use very shallow circuits at arbitrary times.\n", + "- **Trotter error.** The individual product formulas (grey markers) deviate from the exact curve more and more as time grows. The $k=1$ circuit has the largest deviation and is the shallowest, but it is also already in the regime where $t/k \\gtrsim 1$, so the leading $1/k^{2}$ error term is large. The MPF combinations (colored markers) cancel several of these leading Trotter-error terms, so they track the exact curve much more closely than any single $k_j$ circuit. The remaining gap reflects the higher-order Trotter terms that the MPF does *not* cancel: an order-$2$, $r=3$ static MPF only kills the first two error orders, and at large $t/k_{\\min}$ the uncanceled tail eventually dominates — so MPF does not guarantee that very shallow circuits remain accurate at arbitrary times.\n", "\n", "- **Sampling error.** The wider error bars on the MPF curves are a direct consequence of the linear combination: propagating independent per-circuit standard errors $\\sigma_{k_j}$ gives a total variance $\\sigma_{\\text{MPF}}^2 = \\sum_j x_j^2 \\, \\sigma_{k_j}^2$. Therefore, the larger the $\\|x\\|_2$ (and in practice the $\\|x\\|_1$, which is what we control), the more shots are required to reach a given target uncertainty. This is the trade-off behind the approximate-solver option in the Background: we cap $\\|x\\|_1$ to keep this overhead manageable. Crucially, unlike Trotter error, sampling error shrinks with $1/\\sqrt{N_{\\text{shots}}}$, so it can always be reduced by spending more shots.\n", "\n",