From 49823a2483fe171178f14e90abcc30e834cf2ac0 Mon Sep 17 00:00:00 2001 From: Henry Zou Date: Thu, 9 Apr 2026 21:11:46 -0400 Subject: [PATCH 1/2] Revise transpilation-optimizations-with-sabre tutorial Restructure the tutorial to match the standard template format with learning outcomes, prerequisites, and the four-step Qiskit patterns workflow. Key changes: - Remove qiskit_serverless content (runtime performance issues, will revisit separately) - Add small-scale simulator section using qiskit_aer with noise model from real backend, running 10 trials with error bars for statistical reliability - Add large-scale hardware section comparing basic, decay, and lookahead SABRE heuristics across multiple seeds - Improve plots with percentage annotations, value labels, and side-by-side fidelity bar charts - Use consistent "2Q depth" labeling throughout - Add analysis commentary connecting transpilation quality to execution fidelity - Update requirements to Qiskit SDK v2.0+ and add qiskit-aer - Add next steps with links to custom transpiler pass, transpiler plugins, and DAG representation guides - Ran tox -e fix --- ...anspilation-optimizations-with-sabre.ipynb | 1636 +++++++---------- ...280b0b9-6320-43e5-8396-f82f9e718319-0.avif | Bin 0 -> 26319 bytes ...cf9588b-8ea6-4761-b544-14bef8f0be85-0.avif | Bin 12141 -> 0 bytes ...cf9588b-8ea6-4761-b544-14bef8f0be85-1.avif | Bin 11841 -> 0 bytes ...18a8997-d2c7-4661-a6ea-f58eac376bf8-0.avif | Bin 7951 -> 0 bytes ...6dac5ed-a963-458a-ada1-89c915f036e0-0.avif | Bin 0 -> 16693 bytes ...c6cb36f-4bf2-4275-baf5-9557fcba520a-0.avif | Bin 17658 -> 0 bytes ...f75c45a-2c3e-4ef6-8336-0b3f69e6e8fb-0.avif | Bin 0 -> 15983 bytes ...ead9bd2-17e0-4f5b-80bc-eb9b30af052e-0.avif | Bin 0 -> 15367 bytes 9 files changed, 630 insertions(+), 1006 deletions(-) create mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/0280b0b9-6320-43e5-8396-f82f9e718319-0.avif delete mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/4cf9588b-8ea6-4761-b544-14bef8f0be85-0.avif delete mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/4cf9588b-8ea6-4761-b544-14bef8f0be85-1.avif delete mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/818a8997-d2c7-4661-a6ea-f58eac376bf8-0.avif create mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/a6dac5ed-a963-458a-ada1-89c915f036e0-0.avif delete mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/bc6cb36f-4bf2-4275-baf5-9557fcba520a-0.avif create mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/bf75c45a-2c3e-4ef6-8336-0b3f69e6e8fb-0.avif create mode 100644 public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/eead9bd2-17e0-4f5b-80bc-eb9b30af052e-0.avif diff --git a/docs/tutorials/transpilation-optimizations-with-sabre.ipynb b/docs/tutorials/transpilation-optimizations-with-sabre.ipynb index 8dcc3c665cd..97ed5ed9d0b 100644 --- a/docs/tutorials/transpilation-optimizations-with-sabre.ipynb +++ b/docs/tutorials/transpilation-optimizations-with-sabre.ipynb @@ -2,63 +2,63 @@ "cells": [ { "cell_type": "markdown", - "id": "316f2558-4976-4bc2-b346-a66256f622a6", + "id": "1ed79d34-1831-47cb-9985-5bb7dacc70e0", "metadata": {}, "source": [ "---\n", "title: Transpilation optimizations with SABRE\n", - "description: SABRE is an optimization tool for layout and routing. It is especially effective with large-scale circuits and complex coupling maps,\n", + "description: Optimize quantum circuits using SABRE layout and routing for large-scale hardware execution.\n", "---\n", "\n", "\n", "{/* cspell:ignore ylabel xlabel fontsize sharex edgecolor */}\n", "\n", "# Transpilation Optimizations with SABRE\n", - "*Usage estimate: under one minute on a Heron r2 processor (NOTE: This is an estimate only. Your runtime might vary.)*" + "*Usage estimate: 1 minute on a Heron r2 processor. (NOTE: This is an estimate only. Your runtime may vary.)*" ] }, { "cell_type": "markdown", - "id": "e10fe088-c914-4c6b-be7a-d83dc6166245", + "id": "d6834016-1525-42d7-aa21-0fef9d957ecd", "metadata": {}, "source": [ - "## Background\n", - "Transpilation is a critical step in Qiskit that converts quantum circuits into forms compatible with specific quantum hardware. It involves two key stages: **qubit layout** (mapping logical qubits to physical qubits on the device) and **gate routing** (ensuring multi-qubit gates respect device connectivity by inserting SWAP gates as needed).\n", - "\n", - "SABRE (*SWAP-Based Bidirectional heuristic search algorithm*) is a powerful optimization tool for both layout and routing. It is especially effective for **large-scale circuits** (100+ qubits) and devices with complex coupling maps, like the **IBM® Heron**, where the exponential growth in possible qubit mappings demands efficient solutions.\n", + "## Learning outcomes\n", + "After going through this tutorial, you should understand:\n", + "- How to configure SABRE parameters (`layout_trials`, `swap_trials`, `max_iterations`) to improve transpilation quality\n", + "- The trade-offs between transpilation runtime and circuit quality (depth and gate count)\n", + "- How to customize the SABRE routing heuristic (`basic`, `decay`, `lookahead`) and compare their performance on hardware\n", "\n", - "### Why use SABRE?\n", + "## Prerequisites\n", + "We suggest that you are familiar with the following topics before going through this tutorial:\n", + "- [Transpile circuits](/docs/guides/transpile): overview of transpilation in Qiskit\n", + "- [Transpiler stages](/docs/guides/transpiler-stages): layout and routing stages\n", + "- [Configure preset pass managers](/docs/guides/configure-preset-pass-managers): customizing optimization levels\n", "\n", - "SABRE minimizes the number of SWAP gates and reduces circuit depth, improving circuit performance on real hardware. Its heuristic-based approach makes it ideal for advanced hardware and large, complex circuits. Recent improvements introduced in the [LightSABRE](https://arxiv.org/abs/2409.08368) algorithm further optimize SABRE’s performance, offering faster runtimes and fewer SWAP gates. These enhancements make it even more effective for large-scale circuits.\n", + "## Background\n", "\n", - "### What you’ll learn\n", + "Transpilation converts quantum circuits into forms compatible with specific quantum hardware. Two key stages are **qubit layout** (mapping logical qubits to physical qubits) and **gate routing** (inserting SWAP gates so multi-qubit gates respect device connectivity).\n", "\n", - "This tutorial is divided into two parts:\n", - "1. Learn to use SABRE with **Qiskit patterns** for advanced optimization of large circuits.\n", - "2. Leverage **qiskit_serverless** to maximize SABRE’s potential for scalable and efficient transpilation.\n", + "**SABRE** (*SWAP-Based Bidirectional heuristic search algorithm*) optimizes both layout and routing. It is especially effective for large-scale circuits (100+ qubits) on devices with complex coupling maps, like IBM® Heron processors. SABRE minimizes SWAP gates and reduces circuit depth, improving execution fidelity. Recent improvements in the [LightSABRE](https://arxiv.org/abs/2409.08368) algorithm further reduce runtimes and gate counts.\n", "\n", - "You will:\n", - "- Optimize SABRE for circuits with 100+ qubits, surpassing default transpilation settings like `optimization_level=3`.\n", - "- Explore **LightSABRE enhancements** that improve runtime and reduce gate counts.\n", - "- Customize key SABRE parameters (`swap_trials`, `layout_trials`, `max_iterations`, `heuristic`) to balance **circuit quality** and **transpilation runtime**." + "In this tutorial, you will first configure `SabreLayout` with different parameters to optimize a small GHZ circuit and observe the impact on execution fidelity. Then, you will compare SABRE's routing heuristics at scale on real hardware." ] }, { "cell_type": "markdown", - "id": "b6099f09-341e-4895-9d38-48538836e155", + "id": "50cf9d9f-c875-49d5-83b0-c691363615ab", "metadata": {}, "source": [ "## Requirements\n", "\n", "Before starting this tutorial, be sure you have the following installed:\n", - "- Qiskit SDK v1.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n", - "- Qiskit Runtime v0.28 or later (`pip install qiskit-ibm-runtime`)\n", - "- Serverless (`pip install qiskit-ibm-catalog qiskit_serverless`)" + "- 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 (`pip install qiskit-aer`)" ] }, { "cell_type": "markdown", - "id": "131313f1-cad4-4b80-b60d-981ece02295a", + "id": "6d9ad2c3-1b10-4a22-8b75-608869be0ac7", "metadata": {}, "source": [ "## Setup" @@ -66,221 +66,139 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "208d379b-10ee-4d7c-9062-35b15fd18d94", + "execution_count": null, + "id": "6d93c123-b92e-434d-8361-8115509e6d5f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Using backend: ibm_pittsburgh\n" + ] + } + ], "source": [ "from qiskit import QuantumCircuit\n", "from qiskit.quantum_info import SparsePauliOp\n", - "from qiskit_ibm_catalog import QiskitServerless, QiskitFunction\n", "from qiskit_ibm_runtime import QiskitRuntimeService\n", "from qiskit_ibm_runtime import EstimatorOptions\n", "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n", + "from qiskit_aer.primitives import EstimatorV2 as AerEstimator\n", "from qiskit.transpiler import CouplingMap\n", "from qiskit.transpiler.passes import SabreLayout, SabreSwap\n", "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "import time" + "import time\n", + "\n", + "seed = 42\n", + "\n", + "service = QiskitRuntimeService(\n", + " channel=\"ibm_cloud\",\n", + " token=\"\", # Replace with your actual API token\n", + " instance=\"\", # Replace with your instance name if needed\n", + ")\n", + "backend = service.least_busy(operational=True, simulator=False)\n", + "\n", + "\n", + "print(f\"Using backend: {backend.name}\")" ] }, { "cell_type": "markdown", - "id": "c2ac52a8-697e-49bb-9780-fa30213c44fe", + "id": "c34842c6-5e1b-4658-8e91-15149280c783", "metadata": {}, "source": [ - "## Part I. Using SABRE with Qiskit patterns\n", - "\n", - "SABRE can be used in Qiskit to optimize quantum circuits by handling both the qubit layout and gate routing stages. In this section, we’ll guide you through the **minimal example** of using SABRE with Qiskit patterns, with the primary focus on step 2 of optimization.\n", - "\n", - "To run SABRE, you need:\n", - "- A **DAG** (Directed Acyclic Graph) representation of your quantum circuit.\n", - "- The **coupling map** from the backend, which specifies how qubits are physically connected.\n", - "- The **SABRE pass**, which applies the algorithm to optimize the layout and routing.\n", + "## Small-scale simulator example\n", "\n", - "For this part, we’ll focus on the **SabreLayout** pass. It performs both layout and routing trials, working to find the most efficient initial layout while minimizing the number of SWAP gates needed. Importantly, `SabreLayout`, just by itself, internally optimizes both the layout and routing by storing the solution that adds the least number of SWAP gates. Note that when using just **SabreLayout**, we cannot change the heuristic of SABRE, but we are able to customize the number of `layout_trials`." + "In this section, we use a **noisy simulator** based on the real backend's noise model to demonstrate how different `SabreLayout` configurations affect both transpilation quality and execution fidelity. Using `qiskit_aer` with a noise model derived from actual hardware calibration data lets us iterate quickly without consuming hardware credits." ] }, { - "attachments": {}, "cell_type": "markdown", - "id": "888f597b-cce4-48df-b75c-773170260f24", + "id": "a2bcc2b2-727b-447f-b680-a23e3b9e0c3c", "metadata": {}, "source": [ "### Step 1: Map classical inputs to a quantum problem\n", "\n", - "A **GHZ (Greenberger-Horne-Zeilinger)** circuit is a quantum circuit that prepares an entangled state where all qubits are either in the `|0...0⟩` or `|1...1⟩` state. The GHZ state for $n$ qubits is mathematically represented as:\n", - "$$ |\\text{GHZ}\\rangle = \\frac{1}{\\sqrt{2}} \\left( |0\\rangle^{\\otimes n} + |1\\rangle^{\\otimes n} \\right) $$\n", + "We construct a **star-topology GHZ circuit** with 15 qubits. The first qubit is the hub, with CNOT gates connecting it directly to every other qubit. This topology creates a challenging layout problem because it does not map trivially to the device's coupling map.\n", "\n", - "It is constructed by applying:\n", - "1. A Hadamard gate to the first qubit to create superposition.\n", - "2. A series of CNOT gates to entangle the remaining qubits with the first.\n", + "We also define `ZZ` operators to measure entanglement correlations $\\langle Z_0 Z_i \\rangle$ across qubit pairs.\n", "\n", - "For this example, we intentionally construct a **star-topology GHZ circuit** instead of a linear-topology one. In the star topology, the first qubit acts as the \"hub,\" and all other qubits are entangled directly with it using CNOT gates. This choice is deliberate because, while the **linear topology GHZ state** can theoretically be implemented in $ O(N) $ depth on a linear coupling map without any SWAP gates, SABRE would trivially find an optimal solution by mapping a 100-qubit GHZ circuit to a subgraph of the backend's heavy-hex coupling map.\n", - "\n", - "The **star topology GHZ circuit** poses a significantly more challenging problem. Although it can still theoretically be executed in $ O(N) $ depth without SWAP gates, finding this solution requires identifying an optimal initial layout, which is much harder due to the non-linear connectivity of the circuit. This topology serves as a better test case for evaluating SABRE, as it demonstrates how configuration parameters impact layout and routing performance under more complex conditions.\n", - "\n", - "![ghz_star_topology.png](/docs/images/tutorials/transpilation-optimizations-with-sabre/ghz_star_topology.avif)\n", - "\n", - "Notably:\n", - "- The **HighLevelSynthesis** tool can produce the optimal $ O(N) $ depth solution for the star topology GHZ circuit without introducing SWAP gates, like shown in the image above.\n", - "- Alternatively, the **StarPrerouting** pass can reduce the depth further by guiding SABRE's routing decisions, though it may still introduce some SWAP gates. However, StarPrerouting increases runtime and requires integration into the initial transpilation process.\n", - "\n", - "For the purposes of this tutorial, we exclude both HighLevelSynthesis and StarPrerouting to isolate and highlight the direct impact of SABRE configuration on runtime and circuit depth. By measuring the expectation value $ \\langle Z_0 Z_i \\rangle $ for each qubit pair, we analyze:\n", - "- How well SABRE reduces SWAP gates and circuit depth.\n", - "- The effect of these optimizations on the fidelity of the executed circuit, where deviations from $ \\langle Z_0 Z_i \\rangle = 1 $ indicate loss of entanglement.!" + "![ghz_star_topology.png](/docs/images/tutorials/transpilation-optimizations-with-sabre/ghz_star_topology.avif)" ] }, { "cell_type": "code", - "execution_count": 2, - "id": "1d77f7e1-8815-4aec-ab54-93efd735ae38", + "execution_count": 13, + "id": "08a8c4df-b1a5-45b7-9808-ca4e5d7631d8", "metadata": {}, "outputs": [], "source": [ - "# set seed for reproducibility\n", - "seed = 42\n", - "num_qubits = 110\n", + "num_qubits_sim = 15\n", "\n", - "# Create GHZ circuit\n", - "qc = QuantumCircuit(num_qubits)\n", - "qc.h(0)\n", - "for i in range(1, num_qubits):\n", - " qc.cx(0, i)\n", + "# Create star-topology GHZ circuit\n", + "qc_sim = QuantumCircuit(num_qubits_sim)\n", + "qc_sim.h(0)\n", + "for i in range(1, num_qubits_sim):\n", + " qc_sim.cx(0, i)\n", + "qc_sim.measure_all()\n", "\n", - "qc.measure_all()" - ] - }, - { - "cell_type": "markdown", - "id": "24018506-2ab5-4ff3-94b8-f173fb8b2673", - "metadata": {}, - "source": [ - "Next, we will map the operators of interest to evaluate the behavior of the system. Specifically, we will use `ZZ` operators between qubits to examine how the entanglement degrades as the qubits become farther apart. This analysis is critical because inaccuracies in the expectation values $\\langle Z_0 Z_i \\rangle$ for distant qubits can reveal the impact of noise and errors in the circuit execution. By studying these deviations, we gain insight into how well the circuit preserves entanglement under different SABRE configurations and how effectively SABRE minimizes the impact of hardware constraints." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9df28ec1-e572-47d7-bb84-457394129659", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['ZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZIII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZII', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZI', 'ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZ']\n", - "109\n" - ] - } - ], - "source": [ - "# ZZII...II, ZIZI...II, ... , ZIII...IZ\n", - "operator_strings = [\n", - " \"Z\" + \"I\" * i + \"Z\" + \"I\" * (num_qubits - 2 - i)\n", - " for i in range(num_qubits - 1)\n", + "# ZZ operators: Z on qubit 0 and qubit i, identity elsewhere\n", + "operator_strings_sim = [\n", + " \"Z\" + \"I\" * i + \"Z\" + \"I\" * (num_qubits_sim - 2 - i)\n", + " for i in range(num_qubits_sim - 1)\n", "]\n", - "print(operator_strings)\n", - "print(len(operator_strings))\n", - "\n", - "operators = [SparsePauliOp(operator) for operator in operator_strings]" + "operators_sim = [SparsePauliOp(op) for op in operator_strings_sim]" ] }, { "cell_type": "markdown", - "id": "15400bae-af90-40d8-87c1-1637b8f226e2", + "id": "25ac8d92-6362-4d4e-a133-2914703df658", "metadata": {}, "source": [ "### Step 2: Optimize problem for quantum hardware execution\n", "\n", - "In this step, we focus on optimizing the circuit layout for execution on a specific quantum hardware device with 127 qubits. This is the main focus of the tutorial, as we perform **SABRE optimizations and transpilation** to achieve the best circuit performance. Using the `SabreLayout` pass, we determine an initial qubit mapping that minimizes the need for SWAP gates during routing. By passing the `coupling_map` of the target backend, `SabreLayout` adapts the layout to the device's connectivity constraints.\n", + "We create three pass managers with `optimization_level=3`, each with different `SabreLayout` configurations:\n", "\n", - "We will use `generate_preset_pass_manager` with `optimization_level=3` for the transpilation process and customize the `SabreLayout` pass with different configurations. The goal is to find a setup that produces a transpiled circuit with the **lowest size and/or depth**, demonstrating the impact of SABRE optimizations.\n", + "| Config | `max_iterations` | `layout_trials` | `swap_trials` |\n", + "|--------|----------------:|----------------:|--------------:|\n", + "| `pm_1` (default) | 4 | 20 | 20 |\n", + "| `pm_2` | 4 | 200 | 200 |\n", + "| `pm_3` | 8 | 200 | 200 |\n", "\n", - "#### Why Are Circuit Size and Depth Important?\n", + "**Key parameters:**\n", + "- **`layout_trials` / `swap_trials`**: Control how many candidate layouts and routing solutions SABRE explores. More trials means SABRE samples a wider search space, increasing the chance of finding a better solution.\n", + "- **`max_iterations`**: Controls how many forward-backward routing refinement cycles SABRE performs on each candidate. More iterations let SABRE iteratively improve the layout by learning from routing feedback.\n", "\n", - "- **Lower size (gate count):** Reduces the number of operations, minimizing opportunities for errors to accumulate.\n", - "- **Lower depth:** Shortens the overall execution time, which is critical for avoiding decoherence and maintaining quantum state fidelity.\n", - "\n", - "By optimizing these metrics, we improve the circuit’s reliability and execution accuracy on noisy quantum hardware." - ] - }, - { - "cell_type": "markdown", - "id": "21bb1821-ebcd-43f2-b48b-a93db99d872b", - "metadata": {}, - "source": [ - "Select the backend." + "Both come at the cost of longer transpilation time, but the resulting circuits are shorter and use fewer gates, which directly reduces decoherence and gate errors on real hardware." ] }, { "cell_type": "code", - "execution_count": 4, - "id": "6bb232e5-cb6c-45b3-9bfa-ec027046bfab", + "execution_count": 14, + "id": "fd52f8dd-862b-46e2-b93d-0b35f47a3d83", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Using backend: ibm_boston\n" + "pm_1 (4,20,20): 2Q Depth 38, Size 183, Time 0.01s\n", + "pm_2 (4,200,200): 2Q Depth 36, Size 183, Time 0.12s\n", + "pm_3 (8,200,200): 2Q Depth 30, Size 158, Time 0.12s\n", + "\n", + "Improvement vs. default (pm_1):\n", + " pm_2 (4,200,200): 2Q depth +5.3%, size +0.0%\n", + " pm_3 (8,200,200): 2Q depth +21.1%, size +13.7%\n" ] } ], "source": [ - "service = QiskitRuntimeService()\n", - "# backend = service.least_busy(\n", - "# operational=True, simulator=False, min_num_qubits=127\n", - "# )\n", - "backend = service.backend(\"ibm_boston\")\n", - "print(f\"Using backend: {backend.name}\")" - ] - }, - { - "cell_type": "markdown", - "id": "e17c1fd9-7d62-4c33-b5ff-c9d4e0596651", - "metadata": {}, - "source": [ - "To evaluate the impact of different configurations on circuit optimization, we will create three pass managers, each with unique settings for the `SabreLayout` pass. These configurations help analyze the trade-off between circuit quality and transpilation time.\n", - "\n", - "#### Key parameters\n", - "- **`max_iterations`**: The number of forward-backward routing iterations to refine the layout and reduce routing costs.\n", - "- **`layout_trials`**: The number of random initial layouts tested, selecting the one that minimizes SWAP gates.\n", - "- **`swap_trials`**: The number of routing trials for each layout, refining gate placement for better routing.\n", - "\n", - "Increase `layout_trials` and `swap_trials` to perform more thorough optimization, at the cost of increased transpilation time.\n", - "\n", - "#### Configurations in this tutorial\n", - "1. **`pm_1`**: Default settings with `optimization_level=3`.\n", - " - `max_iterations=4`\n", - " - `layout_trials=20`\n", - " - `swap_trials=20`\n", - "\n", - "2. **`pm_2`**: Increases the number of trials for better exploration.\n", - " - `max_iterations=4`\n", - " - `layout_trials=200`\n", - " - `swap_trials=200`\n", - "\n", - "3. **`pm_3`**: Extends `pm_2` by increasing the number of iterations for further refinement.\n", - " - `max_iterations=8`\n", - " - `layout_trials=200`\n", - " - `swap_trials=200`\n", - "\n", - "By comparing the results of these configurations, we aim to determine which achieves the best balance between circuit quality (for example, size and depth) and computational cost." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "2c1535af-a7ea-4439-b7f4-fd0aa9285930", - "metadata": {}, - "outputs": [], - "source": [ - "# Get the coupling map from the backend\n", "cmap = CouplingMap(backend().configuration().coupling_map)\n", "\n", - "# Create the SabreLayout passes for the custom configurations\n", + "# Custom SabreLayout passes\n", "sl_2 = SabreLayout(\n", " coupling_map=cmap,\n", " seed=seed,\n", @@ -296,7 +214,7 @@ " swap_trials=200,\n", ")\n", "\n", - "# Create the pass managers, need to first create then configure the SabreLayout passes\n", + "# Create pass managers and customize SabreLayout (index 2 in the layout stage)\n", "pm_1 = generate_preset_pass_manager(\n", " optimization_level=3, backend=backend, seed_transpiler=seed\n", ")\n", @@ -305,128 +223,63 @@ ")\n", "pm_3 = generate_preset_pass_manager(\n", " optimization_level=3, backend=backend, seed_transpiler=seed\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "d899d9fd-b72d-4930-b337-e67c98307b76", - "metadata": {}, - "source": [ - "Now we can configure the `SabreLayout` pass in the custom pass managers. To do this we know that for the default `generate_preset_pass_manager` on `optimization_level=3`, the `SabreLayout` pass is at index 2, as `SabreLayout` occurs after `SetLayout` and `VF2Laout` passes. We can access this pass and modify its parameters." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "98d7901c-bc20-434b-881d-ac0e841907f8", - "metadata": {}, - "outputs": [], - "source": [ - "pm_2.layout.replace(index=2, passes=sl_2)\n", - "pm_3.layout.replace(index=2, passes=sl_3)" - ] - }, - { - "cell_type": "markdown", - "id": "26e8bcee-a8ef-4603-a5ec-92ca7cea6799", - "metadata": {}, - "source": [ - "With each pass manager configured, we will now execute the transpilation process for each. To compare results, we will track key metrics, including the transpilation time, the depth of the circuit (measured as the two-qubit gate depth), and the total number of gates in the transpiled circuits" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "06dda879-4eb8-4e78-a433-5aaefcd780b0", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Pass manager 1 (4,20,20) : Depth 439, Size 2346, Time 0.5775 s\n", - "Pass manager 2 (4,200,200): Depth 395, Size 2070, Time 3.9927 s\n", - " - Depth improvement: 10.02%\n", - " - Size improvement: 11.76%\n", - " - Time increase: 591.43%\n", - "Pass manager 3 (8,200,200): Depth 375, Size 1873, Time 2.3079 s\n", - " - Depth improvement: 14.58%\n", - " - Size improvement: 20.16%\n", - " - Time increase: 299.67%\n" - ] - } - ], - "source": [ - "# Transpile the circuit with each pass manager and measure the time\n", - "t0 = time.time()\n", - "tqc_1 = pm_1.run(qc)\n", - "t1 = time.time() - t0\n", - "t0 = time.time()\n", - "tqc_2 = pm_2.run(qc)\n", - "t2 = time.time() - t0\n", - "t0 = time.time()\n", - "tqc_3 = pm_3.run(qc)\n", - "t3 = time.time() - t0\n", - "\n", - "# Obtain the depths and the total number of gates (circuit size)\n", - "depth_1 = tqc_1.depth(lambda x: x.operation.num_qubits == 2)\n", - "depth_2 = tqc_2.depth(lambda x: x.operation.num_qubits == 2)\n", - "depth_3 = tqc_3.depth(lambda x: x.operation.num_qubits == 2)\n", - "size_1 = tqc_1.size()\n", - "size_2 = tqc_2.size()\n", - "size_3 = tqc_3.size()\n", - "\n", - "# Transform the observables to match the backend's ISA\n", - "operators_list_1 = [op.apply_layout(tqc_1.layout) for op in operators]\n", - "operators_list_2 = [op.apply_layout(tqc_2.layout) for op in operators]\n", - "operators_list_3 = [op.apply_layout(tqc_3.layout) for op in operators]\n", - "\n", - "# Compute improvements compared to pass manager 1 (default)\n", - "depth_improvement_2 = ((depth_1 - depth_2) / depth_1) * 100\n", - "depth_improvement_3 = ((depth_1 - depth_3) / depth_1) * 100\n", - "size_improvement_2 = ((size_1 - size_2) / size_1) * 100\n", - "size_improvement_3 = ((size_1 - size_3) / size_1) * 100\n", - "time_increase_2 = ((t2 - t1) / t1) * 100\n", - "time_increase_3 = ((t3 - t1) / t1) * 100\n", - "\n", - "print(\n", - " f\"Pass manager 1 (4,20,20) : Depth {depth_1}, Size {size_1}, Time {t1:.4f} s\"\n", - ")\n", - "print(\n", - " f\"Pass manager 2 (4,200,200): Depth {depth_2}, Size {size_2}, Time {t2:.4f} s\"\n", - ")\n", - "print(f\" - Depth improvement: {depth_improvement_2:.2f}%\")\n", - "print(f\" - Size improvement: {size_improvement_2:.2f}%\")\n", - "print(f\" - Time increase: {time_increase_2:.2f}%\")\n", - "print(\n", - " f\"Pass manager 3 (8,200,200): Depth {depth_3}, Size {size_3}, Time {t3:.4f} s\"\n", ")\n", - "print(f\" - Depth improvement: {depth_improvement_3:.2f}%\")\n", - "print(f\" - Size improvement: {size_improvement_3:.2f}%\")\n", - "print(f\" - Time increase: {time_increase_3:.2f}%\")" + "\n", + "pm_2.layout.replace(index=2, passes=sl_2)\n", + "pm_3.layout.replace(index=2, passes=sl_3)\n", + "\n", + "# Transpile and collect metrics\n", + "results_sim = {}\n", + "for name, pm in [\n", + " (\"pm_1 (4,20,20)\", pm_1),\n", + " (\"pm_2 (4,200,200)\", pm_2),\n", + " (\"pm_3 (8,200,200)\", pm_3),\n", + "]:\n", + " t0 = time.time()\n", + " tqc = pm.run(qc_sim)\n", + " elapsed = time.time() - t0\n", + " depth = tqc.depth(lambda x: x.operation.num_qubits == 2)\n", + " size = tqc.size()\n", + " ops_mapped = [op.apply_layout(tqc.layout) for op in operators_sim]\n", + " results_sim[name] = {\n", + " \"tqc\": tqc,\n", + " \"ops\": ops_mapped,\n", + " \"depth\": depth,\n", + " \"size\": size,\n", + " \"time\": elapsed,\n", + " }\n", + " print(f\"{name}: 2Q Depth {depth}, Size {size}, Time {elapsed:.2f}s\")\n", + "\n", + "# Print improvement relative to default (pm_1)\n", + "baseline = results_sim[\"pm_1 (4,20,20)\"]\n", + "print(\"\\nImprovement vs. default (pm_1):\")\n", + "for name in [\"pm_2 (4,200,200)\", \"pm_3 (8,200,200)\"]:\n", + " r = results_sim[name]\n", + " depth_pct = (baseline[\"depth\"] - r[\"depth\"]) / baseline[\"depth\"] * 100\n", + " size_pct = (baseline[\"size\"] - r[\"size\"]) / baseline[\"size\"] * 100\n", + " print(f\" {name}: 2Q depth {depth_pct:+.1f}%, size {size_pct:+.1f}%\")" ] }, { "cell_type": "markdown", - "id": "f187b5db-24a0-4080-a6bb-f949f72354ba", + "id": "0c27cbdb-c065-4a36-a0ef-6c9572c7a4a5", "metadata": {}, "source": [ - "The results demonstrate that increasing the number of trials (`layout_trials` and `swap_trials`) can significantly improve circuit quality by reducing both depth and size. However, this improvement often comes at the cost of increased runtime due to the additional computation required to explore more potential layouts and routing paths.\n", + "The more optimized pass managers produced circuits with lower 2Q depth and fewer gates. While this improvement is not guaranteed on every run, it is the general trend: exploring more candidates and refining them with additional iterations gives SABRE a better chance of finding a high-quality layout.\n", "\n", - "Increasing the `max_iterations` can further enhance optimization by refining the layout through more forward-backward routing cycles. In this case, increasing `max_iterations` resulted in the most significant reduction in circuit depth and size, even reducing runtime compared to `pm_2`, likely by streamlining subsequent optimization stages. It’s important to note, however, that the effectiveness of increasing `max_iterations` can vary significantly depending on the circuit. While more iterations may yield better layout and routing choices, they provide no guarantees and depend heavily on the circuit’s structure and the complexity of the connectivity constraints" + "Note that this is a small circuit (15 qubits), so the room for improvement is limited. With larger circuits (100+ qubits), the search space grows dramatically and the benefits of increased trials and iterations become much more pronounced." ] }, { "cell_type": "code", - "execution_count": 8, - "id": "818a8997-d2c7-4661-a6ea-f58eac376bf8", + "execution_count": 15, + "id": "bf75c45a-2c3e-4ef6-8336-0b3f69e6e8fb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "metadata": {}, @@ -434,147 +287,180 @@ } ], "source": [ - "# Plot the results of the metrics\n", - "times = [t1, t2, t3]\n", - "depths = [depth_1, depth_2, depth_3]\n", - "sizes = [size_1, size_2, size_3]\n", - "pm_names = [\n", - " \"pm_1 (4 iter, 20 trials)\",\n", - " \"pm_2 (4 iter, 200 trials)\",\n", - " \"pm_3 (8 iter, 200 trials)\",\n", - "]\n", - "colors = plt.cm.viridis(np.linspace(0.2, 0.8, len(pm_names)))\n", - "\n", - "# Create a figure with three subplots\n", - "fig, axs = plt.subplots(3, 1, figsize=(6, 9), sharex=True)\n", - "axs[0].bar(pm_names, times, color=colors)\n", - "axs[0].set_ylabel(\"Time (s)\", fontsize=12)\n", - "axs[0].set_title(\"Transpilation Time\", fontsize=14)\n", - "axs[0].grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", - "axs[1].bar(pm_names, depths, color=colors)\n", - "axs[1].set_ylabel(\"Depth\", fontsize=12)\n", - "axs[1].set_title(\"Circuit Depth\", fontsize=14)\n", - "axs[1].grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", - "axs[2].bar(pm_names, sizes, color=colors)\n", - "axs[2].set_ylabel(\"Size\", fontsize=12)\n", - "axs[2].set_title(\"Circuit Size\", fontsize=14)\n", - "axs[2].set_xticks(range(len(pm_names)))\n", - "axs[2].set_xticklabels(pm_names, fontsize=10, rotation=15)\n", - "axs[2].grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", - "\n", - "# Add some spacing between subplots\n", + "pm_names = list(results_sim.keys())\n", + "depths = [results_sim[n][\"depth\"] for n in pm_names]\n", + "sizes = [results_sim[n][\"size\"] for n in pm_names]\n", + "times = [results_sim[n][\"time\"] for n in pm_names]\n", + "colors = [\"#404080\", \"#2a9d8f\", \"#a8d05e\"]\n", + "x = np.arange(len(pm_names))\n", + "\n", + "fig, axs = plt.subplots(1, 3, figsize=(14, 5))\n", + "\n", + "# 2Q Depth\n", + "bars = axs[0].bar(x, depths, color=colors)\n", + "axs[0].set_ylabel(\"2Q Depth\", fontsize=11)\n", + "axs[0].set_title(\"Two-Qubit Gate Depth\", fontsize=13)\n", + "axs[0].set_ylim(0, max(depths) * 1.2)\n", + "for bar, val in zip(bars, depths):\n", + " axs[0].text(\n", + " bar.get_x() + bar.get_width() / 2,\n", + " bar.get_height() + max(depths) * 0.02,\n", + " str(val),\n", + " ha=\"center\",\n", + " va=\"bottom\",\n", + " fontsize=11,\n", + " fontweight=\"bold\",\n", + " )\n", + "for i in range(1, len(depths)):\n", + " pct = (depths[0] - depths[i]) / depths[0] * 100\n", + " if pct != 0:\n", + " axs[0].text(\n", + " bars[i].get_x() + bars[i].get_width() / 2,\n", + " bars[i].get_height() / 2,\n", + " f\"{pct:+.0f}%\",\n", + " ha=\"center\",\n", + " va=\"center\",\n", + " fontsize=10,\n", + " color=\"white\",\n", + " fontweight=\"bold\",\n", + " )\n", + "\n", + "# Size\n", + "bars = axs[1].bar(x, sizes, color=colors)\n", + "axs[1].set_ylabel(\"Gate Count\", fontsize=11)\n", + "axs[1].set_title(\"Circuit Size\", fontsize=13)\n", + "axs[1].set_ylim(0, max(sizes) * 1.2)\n", + "for bar, val in zip(bars, sizes):\n", + " axs[1].text(\n", + " bar.get_x() + bar.get_width() / 2,\n", + " bar.get_height() + max(sizes) * 0.02,\n", + " str(val),\n", + " ha=\"center\",\n", + " va=\"bottom\",\n", + " fontsize=11,\n", + " fontweight=\"bold\",\n", + " )\n", + "for i in range(1, len(sizes)):\n", + " pct = (sizes[0] - sizes[i]) / sizes[0] * 100\n", + " if abs(pct) > 0.1:\n", + " axs[1].text(\n", + " bars[i].get_x() + bars[i].get_width() / 2,\n", + " bars[i].get_height() / 2,\n", + " f\"{pct:+.0f}%\",\n", + " ha=\"center\",\n", + " va=\"center\",\n", + " fontsize=10,\n", + " color=\"white\",\n", + " fontweight=\"bold\",\n", + " )\n", + "\n", + "# Time\n", + "bars = axs[2].bar(x, times, color=colors)\n", + "axs[2].set_ylabel(\"Time (s)\", fontsize=11)\n", + "axs[2].set_title(\"Transpilation Time\", fontsize=13)\n", + "axs[2].set_ylim(0, max(times) * 1.3)\n", + "for bar, val in zip(bars, times):\n", + " axs[2].text(\n", + " bar.get_x() + bar.get_width() / 2,\n", + " bar.get_height() + max(times) * 0.03,\n", + " f\"{val:.2f}s\",\n", + " ha=\"center\",\n", + " va=\"bottom\",\n", + " fontsize=11,\n", + " fontweight=\"bold\",\n", + " )\n", + "\n", + "for ax in axs:\n", + " ax.set_xticks(x)\n", + " ax.set_xticklabels(pm_names, fontsize=9, rotation=15)\n", + " ax.grid(axis=\"y\", linestyle=\"--\", alpha=0.5)\n", + "\n", + "plt.suptitle(\n", + " \"Transpilation quality vs. SABRE configuration\",\n", + " fontsize=14,\n", + " fontweight=\"bold\",\n", + " y=1.02,\n", + ")\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", - "id": "13a9127a-aee2-447c-8921-f6d26caac84c", + "id": "6a233965-1358-420b-8823-5f4e206090b4", "metadata": {}, "source": [ "### Step 3: Execute using Qiskit primitives\n", "\n", - "In this step, we use the `Estimator` primitive to calculate the expectation values $\\langle Z_0 Z_i \\rangle$ for the `ZZ` operators, evaluating the entanglement and execution quality of the transpiled circuits. To align with typical user workflows, we submit the job for execution and apply error suppression using **dynamical decoupling**, a technique that mitigates decoherence by inserting gate sequences to preserve qubit states. Additionally, we specify a resilience level to counteract noise, with higher levels providing more accurate results at the cost of increased processing time. This approach assesses the performance of each pass manager configuration under realistic execution conditions." + "We run each transpiled circuit **10 times** using the Aer `EstimatorV2` with a noise model derived from the real backend. Since noisy simulation results vary between runs, averaging over multiple runs gives more reliable fidelity estimates and lets us quantify the statistical uncertainty with error bars." ] }, { "cell_type": "code", - "execution_count": 9, - "id": "4ca2c383-f58c-457e-9394-2e0e8ef38d5a", + "execution_count": null, + "id": "a91b9887-c8cf-48fd-a6fb-a5506d201f8d", "metadata": {}, "outputs": [], "source": [ - "options = EstimatorOptions()\n", - "options.resilience_level = 2\n", - "options.dynamical_decoupling.enable = True\n", - "options.dynamical_decoupling.sequence_type = \"XY4\"\n", + "# Create a noisy estimator from the real backend's noise model\n", + "noisy_estimator = AerEstimator.from_backend(backend)\n", "\n", - "# Create an Estimator object\n", - "estimator = Estimator(backend, options=options)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "bde39e77-e4f2-43bf-a9c4-8b9d444a6e82", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "d5k0qs7853es738dab6g\n", - "d5k0qsf853es738dab70\n", - "d5k0qsf853es738dab7g\n" - ] - } - ], - "source": [ - "# Submit the circuit to Estimator\n", - "job_1 = estimator.run([(tqc_1, operators_list_1)])\n", - "job_1_id = job_1.job_id()\n", - "print(job_1_id)\n", - "\n", - "job_2 = estimator.run([(tqc_2, operators_list_2)])\n", - "job_2_id = job_2.job_id()\n", - "print(job_2_id)\n", - "\n", - "job_3 = estimator.run([(tqc_3, operators_list_3)])\n", - "job_3_id = job_3.job_id()\n", - "print(job_3_id)" + "num_runs = 10\n", + "# sim_all_runs[name] = list of arrays, one per run\n", + "sim_all_runs = {name: [] for name in results_sim}\n", + "\n", + "for run in range(num_runs):\n", + " for name, r in results_sim.items():\n", + " job = noisy_estimator.run([(r[\"tqc\"], r[\"ops\"])])\n", + " evs = list(job.result()[0].data.evs)\n", + " sim_all_runs[name].append(evs)\n", + " print(f\"Run {run + 1}/{num_runs} done\")\n", + "\n", + "# Compute mean and std across runs for each config\n", + "sim_stats = {}\n", + "for name in results_sim:\n", + " all_evs = np.array(sim_all_runs[name]) # shape (num_runs, num_operators)\n", + " sim_stats[name] = {\n", + " \"mean\": np.mean(all_evs, axis=0),\n", + " \"std\": np.std(all_evs, axis=0),\n", + " \"overall_mean\": np.mean(all_evs),\n", + " \"overall_std\": np.std(\n", + " np.mean(all_evs, axis=1)\n", + " ), # std of per-run averages\n", + " }\n", + " print(\n", + " f\"{name}: mean fidelity = {sim_stats[name]['overall_mean']:.4f} +/- {sim_stats[name]['overall_std']:.4f}\"\n", + " )" ] }, { - "cell_type": "code", - "execution_count": 11, - "id": "a5d36e34-c725-414d-af94-ff48fc139b81", + "cell_type": "markdown", + "id": "89e6c70f-4da4-470f-b0fa-2e2521c82f6f", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Job 1 done\n", - "Job 2 done\n", - "Job 3 done\n" - ] - } - ], "source": [ - "# Run the jobs\n", - "result_1 = job_1.result()[0]\n", - "print(\"Job 1 done\")\n", - "result_2 = job_2.result()[0]\n", - "print(\"Job 2 done\")\n", - "result_3 = job_3.result()[0]\n", - "print(\"Job 3 done\")" + "Because this is a small circuit, we expect the fidelity values to be relatively close across all three configurations. The circuits are short enough that hardware noise does not heavily penalize even the least optimized version. Still, we can see a consistent improvement in mean fidelity for the configurations that produced lower 2Q depth and gate count, confirming that transpilation quality has a measurable impact even at small scale." ] }, { "cell_type": "markdown", - "id": "30899adf-e2a1-4ca0-867c-1ac994bb2206", + "id": "e601648b-8f5f-4111-ba35-f64af63da909", "metadata": {}, "source": [ "### Step 4: Post-process and return result in desired classical format\n", "\n", - "Once the job completes, we analyze the results by plotting the expectation values $\\langle Z_0 Z_i \\rangle$ for each qubit. In an ideal simulation, all $\\langle Z_0 Z_i \\rangle$ values should be 1, reflecting perfect entanglement across the qubits. However, due to noise and hardware constraints, the expectation values typically decrease as `i` increases, revealing how entanglement degrades over distance.\n", - "\n", - "In this step, we compare the results from each pass manager configuration to the ideal simulation. By examining the deviation of $\\langle Z_0 Z_i \\rangle$ from 1 for each configuration, we can quantify how well each pass manager preserves entanglement and mitigates the effects of noise. This analysis directly assesses the impact of SABRE optimizations on execution fidelity and highlights which configuration best balances optimization quality and execution performance.\n", - "\n", - "\n", - "The results will be visualized to highlight differences across pass managers, showcasing how improvements in layout and routing influence the final circuit execution on noisy quantum hardware." + "We plot the entanglement correlations $\\langle Z_0 Z_i \\rangle$ as a function of qubit distance, along with the **mean correlation** as a single fidelity metric. In an ideal (noiseless) case, all correlations would be 1. With realistic noise, each additional gate introduces error and each additional time step allows decoherence, so a transpiled circuit with lower depth and fewer gates (especially two-qubit gates) should preserve entanglement better." ] }, { "cell_type": "code", - "execution_count": 12, - "id": "bc6cb36f-4bf2-4275-baf5-9557fcba520a", + "execution_count": 17, + "id": "a6dac5ed-a963-458a-ada1-89c915f036e0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "metadata": {}, @@ -582,765 +468,503 @@ } ], "source": [ - "data = list(range(1, len(operators) + 1)) # Distance between the Z operators\n", - "\n", - "values_1 = list(result_1.data.evs)\n", - "values_2 = list(result_2.data.evs)\n", - "values_3 = list(result_3.data.evs)\n", + "data_sim = list(range(1, len(operators_sim) + 1))\n", + "markers = [\"o\", \"s\", \"^\"]\n", + "colors_line = [\"#404080\", \"#2a9d8f\", \"#a8d05e\"]\n", "\n", - "plt.plot(\n", - " data,\n", - " values_1,\n", - " marker=\"o\",\n", - " label=\"pm_1 (iters=4, swap_trials=20, layout_trials=20)\",\n", + "fig, (ax1, ax2) = plt.subplots(\n", + " 1, 2, figsize=(14, 5), gridspec_kw={\"width_ratios\": [2.5, 1]}\n", ")\n", - "plt.plot(\n", - " data,\n", - " values_2,\n", - " marker=\"s\",\n", - " label=\"pm_2 (iters=4, swap_trials=200, layout_trials=200)\",\n", + "\n", + "# Left: correlations vs distance with error bars (mean +/- 1 std)\n", + "for (name, stats), marker, color in zip(\n", + " sim_stats.items(), markers, colors_line\n", + "):\n", + " ax1.errorbar(\n", + " data_sim,\n", + " stats[\"mean\"],\n", + " yerr=stats[\"std\"],\n", + " marker=marker,\n", + " label=name,\n", + " color=color,\n", + " linewidth=2,\n", + " capsize=3,\n", + " capthick=1,\n", + " elinewidth=1,\n", + " )\n", + "\n", + "ax1.set_xlabel(\"Distance between qubits $i$\", fontsize=11)\n", + "ax1.set_ylabel(r\"$\\langle Z_0 Z_i \\rangle$\", fontsize=11)\n", + "ax1.set_title(\n", + " \"Entanglement correlations vs. qubit distance (avg. of 10 runs)\",\n", + " fontsize=12,\n", ")\n", - "plt.plot(\n", - " data,\n", - " values_3,\n", - " marker=\"^\",\n", - " label=\"pm_3 (iters=8, swap_trials=200, layout_trials=200)\",\n", + "ax1.legend(fontsize=9)\n", + "ax1.grid(alpha=0.3)\n", + "\n", + "# Right: mean correlation bar chart with error bars\n", + "names = list(sim_stats.keys())\n", + "means = [sim_stats[n][\"overall_mean\"] for n in names]\n", + "stds = [sim_stats[n][\"overall_std\"] for n in names]\n", + "x_bar = np.arange(len(names))\n", + "bars = ax2.bar(\n", + " x_bar, means, yerr=stds, color=colors_line, capsize=5, ecolor=\"gray\"\n", ")\n", - "plt.xlabel(\"Distance between qubits $i$\")\n", - "plt.ylabel(r\"$\\langle Z_i Z_0 \\rangle / \\langle Z_1 Z_0 \\rangle $\")\n", - "plt.legend()\n", + "ax2.set_ylabel(r\"Mean $\\langle Z_0 Z_i \\rangle$\", fontsize=11)\n", + "ax2.set_title(\"Average fidelity\", fontsize=13)\n", + "y_range = max(means) - min(means) if max(means) != min(means) else 0.01\n", + "ax2.set_ylim(min(means) - y_range * 0.8, max(means) + y_range * 0.8)\n", + "for bar, val, std in zip(bars, means, stds):\n", + " ax2.text(\n", + " bar.get_x() + bar.get_width() / 2,\n", + " bar.get_height() + std + y_range * 0.08,\n", + " f\"{val:.4f}\",\n", + " ha=\"center\",\n", + " va=\"bottom\",\n", + " fontsize=10,\n", + " fontweight=\"bold\",\n", + " )\n", + "# Annotate % improvement vs pm_1\n", + "baseline_mean = means[0]\n", + "for i in range(1, len(means)):\n", + " pct = (means[i] - baseline_mean) / baseline_mean * 100\n", + " if abs(pct) > 0.01:\n", + " mid_y = (means[i] + ax2.get_ylim()[0]) / 2\n", + " ax2.text(\n", + " bars[i].get_x() + bars[i].get_width() / 2,\n", + " mid_y,\n", + " f\"{pct:+.1f}%\",\n", + " ha=\"center\",\n", + " va=\"center\",\n", + " fontsize=10,\n", + " color=\"white\",\n", + " fontweight=\"bold\",\n", + " )\n", + "ax2.set_xticks(x_bar)\n", + "ax2.set_xticklabels(names, fontsize=8, rotation=15)\n", + "ax2.grid(axis=\"y\", linestyle=\"--\", alpha=0.5)\n", + "\n", + "fig.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", - "id": "38a1d768-aa3e-41dc-8af6-e6806f58a85c", + "id": "05235ab1-b473-4267-a34c-5f56e728550b", "metadata": {}, "source": [ - "### Analysis of Results\n", - "\n", - "The plot shows the expectation values $\\langle Z_0 Z_i \\rangle / \\langle Z_0 Z_0 \\rangle$ as a function of the distance between qubits for three pass manager configurations with increasing levels of optimization. In the ideal case, these values remain close to 1, indicating strong correlations across the circuit. As the distance increases, noise and accumulated errors lead to a decay in correlations, revealing how well each transpilation strategy preserves the underlying structure of the state.\n", + "The results show a clear connection between transpilation quality and execution fidelity:\n", "\n", - "Among the three configurations, `pm_1` clearly performs the worst. Its correlation values decay rapidly as the distance increases and approach zero much earlier than the other two configurations. This behavior is consistent with its larger circuit depth and gate count, where accumulated noise quickly degrades long-range correlations.\n", + "- **`pm_1` (default)**: Baseline. With only 20 trials and 4 iterations, SABRE has limited room to optimize, resulting in the deepest circuit.\n", + "- **`pm_2` (more trials)**: Exploring 10x more candidates finds layouts comparable to or slightly better than the default. The improvement depends on how much the search space benefits from broader sampling.\n", + "- **`pm_3` (more trials + more iterations)**: Doubling `max_iterations` to 8 gives SABRE more refinement cycles, producing the shallowest and smallest circuit. This translates to higher mean fidelity because the circuit runs faster (less decoherence) and uses fewer two-qubit gates (fewer error opportunities).\n", "\n", - "Both `pm_2` and `pm_3` represent significant improvements over `pm_1` across essentially all distances. On average, `pm_3` exhibits the strongest overall performance, maintaining higher correlation values over longer distances and showing a more gradual decay. This aligns with its more aggressive optimization, which produces shallower circuits that are generally more robust to noise accumulation.\n", - "\n", - "That said, `pm_2` shows noticeably better accuracy at short distances compared to `pm_3`, despite having a slightly larger depth and gate count. This suggests that circuit depth alone does not fully determine performance; the specific structure produced by the transpilation, including how entangling gates are arranged and how errors propagate through the circuit, also plays an important role. In some cases, the transformations applied by `pm_2` appear to better preserve local correlations, even if they do not scale as well to longer distances.\n", - "\n", - "Taken together, these results highlight a trade-off between circuit compactness and circuit structure. While increased optimization generally improves long-range stability, the best performance for a given observable depends on both reducing circuit depth and producing a structure that is well matched to the noise characteristics of the hardware." + "Note that increasing `max_iterations` does not always have a positive impact. In this case it helped significantly, but for other circuits or backends the additional iterations may not yield further improvement, or may even slightly hurt performance due to over-optimization of a local minimum. In general, you should increase `layout_trials` and `swap_trials` as much as your time budget allows, since more trials always increases the chance of finding a better layout. Increasing `max_iterations` is worth testing but should be validated for your specific use case." ] }, { "cell_type": "markdown", - "id": "33b1f4dd-5d8b-4282-9f69-ced86cc2530b", + "id": "c2b60e42-4aa2-4dc1-8a11-022072e79776", "metadata": {}, "source": [ - "## Part II. Configuring the heuristic in SABRE and using Serverless\n", + "## Large-scale hardware example\n", "\n", - "In addition to adjusting trial numbers, SABRE supports customization of the routing heuristic used during transpilation. By default, `SabreLayout` employs the decay heuristic, which dynamically weights qubits based on their likelihood of being swapped. To use a different heuristic (such as the `lookahead` heuristic), you can create a custom `SabreSwap` pass and connect it to `SabreLayout` by running a `PassManager` with `FullAncillaAllocation`, `EnlargeWithAncilla`, and `ApplyLayout`. When using `SabreSwap` as a parameter for `SabreLayout`, only one layout trial is performed by default. To efficiently run multiple layout trials, we leverage the serverless runtime for parallelization. For more about serverless, see the [Serverless documentation](/docs/guides/serverless).\n", + "In addition to adjusting trial numbers, SABRE supports customizing the **routing heuristic**. SABRE offers three heuristics:\n", + "- **`basic`**: A simple greedy approach that selects the swap minimizing the immediate distance to the next gate.\n", + "- **`decay`** (default): Dynamically weights qubits based on recent activity, discouraging repeated swaps on the same qubits.\n", + "- **`lookahead`**: Evaluates future routing costs by looking ahead at upcoming gates, potentially finding better swap sequences.\n", "\n", - "### How to Change the Routing Heuristic\n", - "1. Create a custom `SabreSwap` pass with the desired heuristic.\n", - "2. Use this custom `SabreSwap` as the routing method for the `SabreLayout` pass.\n", + "To use a custom heuristic, create a `SabreSwap` pass and connect it to `SabreLayout` via the `routing_pass` parameter.\n", "\n", - "While it is possible to run multiple layout trials using a loop, serverless runtime is the better choice for large-scale and more vigorous experiments. Serverless supports parallel execution of layout trials, significantly speeding up the optimization of larger circuits and large experimental sweeps. This makes it especially valuable when working with resource-intensive tasks or when time efficiency is critical.\n", - "\n", - "This section focuses solely on step 2 of optimization: minimizing circuit size and depth to achieve the best possible transpiled circuit. Building on the earlier results, we now explore how heuristic customization and serverless parallelization can further enhance optimization performance, making it suitable for large-scale quantum circuit transpilation." + "Here we compare all three heuristics at scale on a 100-qubit GHZ circuit. We run multiple layout trials with different seeds, select the best transpiled circuit from each heuristic, and submit them to real hardware." ] }, { "cell_type": "markdown", - "id": "38876eac-253f-4882-b468-7618ef0c6ba9", + "id": "d755fafa-bbbc-4191-9ad9-a77f2af1bedc", "metadata": {}, "source": [ - "### Results without serverless runtime (1 layout trial):" + "### Steps 1-4 compress into single code block\n", + "Here we put the full workflow together at a larger scale. When using `SabreSwap` as the `routing_pass` for `SabreLayout`, only one layout trial is performed per call, so we loop over seeds to explore the layout space." ] }, { "cell_type": "code", - "execution_count": 17, - "id": "95a5fb2f-8bca-4418-ad1a-c8da533c111f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Default (heuristic='decay') : Depth 443, Size 3115, Time 1.034372091293335\n", - "Custom (heuristic='lookahead'): Depth 432, Size 2856, Time 0.6669301986694336\n" - ] - } - ], - "source": [ - "swap_trials = 1000\n", - "\n", - "# Default PassManager with `SabreLayout` and `SabreSwap`, using heuristic \"decay\"\n", - "sr_default = SabreSwap(\n", - " coupling_map=cmap, heuristic=\"decay\", trials=swap_trials, seed=seed\n", - ")\n", - "sl_default = SabreLayout(\n", - " coupling_map=cmap, routing_pass=sr_default, seed=seed\n", - ")\n", - "pm_default = generate_preset_pass_manager(\n", - " optimization_level=3, backend=backend, seed_transpiler=seed\n", - ")\n", - "pm_default.layout.replace(index=2, passes=sl_default)\n", - "pm_default.routing.replace(index=1, passes=sr_default)\n", - "\n", - "t0 = time.time()\n", - "tqc_default = pm_default.run(qc)\n", - "t_default = time.time() - t0\n", - "size_default = tqc_default.size()\n", - "depth_default = tqc_default.depth(lambda x: x.operation.num_qubits == 2)\n", - "\n", - "\n", - "# Custom PassManager with `SabreLayout` and `SabreSwap`, using heuristic \"lookahead\"\n", - "sr_custom = SabreSwap(\n", - " coupling_map=cmap, heuristic=\"lookahead\", trials=swap_trials, seed=seed\n", - ")\n", - "sl_custom = SabreLayout(coupling_map=cmap, routing_pass=sr_custom, seed=seed)\n", - "pm_custom = generate_preset_pass_manager(\n", - " optimization_level=3, backend=backend, seed_transpiler=seed\n", - ")\n", - "pm_custom.layout.replace(index=2, passes=sl_custom)\n", - "pm_custom.routing.replace(index=1, passes=sr_custom)\n", - "\n", - "t0 = time.time()\n", - "tqc_custom = pm_custom.run(qc)\n", - "t_custom = time.time() - t0\n", - "size_custom = tqc_custom.size()\n", - "depth_custom = tqc_custom.depth(lambda x: x.operation.num_qubits == 2)\n", - "\n", - "print(\n", - " f\"Default (heuristic='decay') : Depth {depth_default}, Size {size_default}, Time {t_default}\"\n", - ")\n", - "print(\n", - " f\"Custom (heuristic='lookahead'): Depth {depth_custom}, Size {size_custom}, Time {t_custom}\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "25d4519b-e41b-4d9f-9d3c-54e8252409d9", - "metadata": {}, - "source": [ - "Here we see that the `lookahead` heuristic performs better than the `decay` heuristic in terms of circuit depth, size, and time. This improvements highlights how we can improve SABRE beyond just trials and iterations for your specific circuit and hardware constraints. Note that these results are based on a single layout trial. To achieve more accurate results, we recommend running multiple layout trials, which can be done efficiently using the serverless runtime." - ] - }, - { - "cell_type": "markdown", - "id": "eff72eda-87e7-48db-93d5-94d06fe57c80", - "metadata": {}, - "source": [ - "### Results with serverless runtime (multiple layout trials)" - ] - }, - { - "cell_type": "markdown", - "id": "0d6b162b-8a78-4b7b-a497-def00672a816", + "execution_count": 7, + "id": "4feb0fcf-d305-4741-82a7-b0fe0f0894fc", "metadata": {}, - "source": [ - "Qiskit Serverless requires setting up your workload’s `.py` files into a dedicated directory. The following code cell is a Python file in the `source_files` directory named `transpile_remote.py`. This file contains the function that runs the transpilation process." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "0ba37113-8e9b-4797-8e13-915310933100", - "metadata": { - "tags": [ - "remove-cell" - ] - }, "outputs": [], "source": [ - "# This cell is hidden from users, it makes sure the `source_files` directory exists\n", - "from pathlib import Path\n", + "# -------------------------Step 1-------------------------\n", "\n", - "Path(\"source_files\").mkdir(exist_ok=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "7fc69c04-42c4-48f0-9ad5-736343b9d316", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Overwriting source_files/transpile_remote.py\n" - ] - } - ], - "source": [ - "%%writefile source_files/transpile_remote.py\n", - "import time\n", - "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n", - "from qiskit.transpiler.passes import SabreLayout, SabreSwap\n", - "from qiskit.transpiler import CouplingMap\n", - "from qiskit_serverless import get_arguments, save_result, distribute_task, get\n", - "from qiskit_ibm_runtime import QiskitRuntimeService\n", + "num_qubits = 100\n", "\n", - "@distribute_task(target={\n", - " \"cpu\": 1,\n", - " \"mem\": 1024 * 1024 * 1024\n", - "})\n", - "def transpile_remote(qc, optimization_level, backend_name, seed, swap_trials, heuristic):\n", - " \"\"\"Transpiles an abstract circuit into an ISA circuit for a given backend.\"\"\"\n", - "\n", - " service = QiskitRuntimeService()\n", - " backend = service.backend(backend_name)\n", - "\n", - " pm = generate_preset_pass_manager(\n", - " optimization_level=optimization_level,\n", - " backend=backend,\n", - " seed_transpiler=seed\n", - " )\n", + "# Create star-topology GHZ circuit\n", + "qc = QuantumCircuit(num_qubits)\n", + "qc.h(0)\n", + "for i in range(1, num_qubits):\n", + " qc.cx(0, i)\n", + "qc.measure_all()\n", "\n", - " # Changing the `SabreLayout` and `SabreSwap` passes to use the custom configurations\n", - " cmap = CouplingMap(backend().configuration().coupling_map)\n", - " sr = SabreSwap(coupling_map=cmap, heuristic=heuristic, trials=swap_trials, seed=seed)\n", - " sl = SabreLayout(coupling_map=cmap, routing_pass=sr, seed=seed)\n", - " pm.layout.replace(index=2, passes=sl)\n", - " pm.routing.replace(index=1, passes=sr)\n", - "\n", - " # Measure the transpile time\n", - " start_time = time.time() # Start timer\n", - " tqc = pm.run(qc) # Transpile the circuit\n", - " end_time = time.time() # End timer\n", - "\n", - " transpile_time = end_time - start_time # Calculate the elapsed time\n", - " return tqc, transpile_time # Return both the transpiled circuit and the transpile time\n", - "\n", - "\n", - "# Get program arguments\n", - "arguments = get_arguments()\n", - "circuit = arguments.get(\"circuit\")\n", - "backend_name = arguments.get(\"backend_name\")\n", - "optimization_level = arguments.get(\"optimization_level\")\n", - "seed_list = arguments.get(\"seed_list\")\n", - "swap_trials = arguments.get(\"swap_trials\")\n", - "heuristic = arguments.get(\"heuristic\")\n", - "\n", - "# Transpile the circuits\n", - "transpile_worker_references = [\n", - " transpile_remote(circuit, optimization_level, backend_name, seed, swap_trials, heuristic)\n", - " for seed in seed_list\n", + "# ZZ operators\n", + "operator_strings = [\n", + " \"Z\" + \"I\" * i + \"Z\" + \"I\" * (num_qubits - 2 - i)\n", + " for i in range(num_qubits - 1)\n", "]\n", - "\n", - "results_with_times = get(transpile_worker_references)\n", - "\n", - "# Separate the transpiled circuits and their transpile times\n", - "transpiled_circuits = [result[0] for result in results_with_times]\n", - "transpile_times = [result[1] for result in results_with_times]\n", - "\n", - "# Save both results and transpile times\n", - "save_result({\"transpiled_circuits\": transpiled_circuits, \"transpile_times\": transpile_times})" - ] - }, - { - "cell_type": "markdown", - "id": "fefed67d-3499-4049-a3fa-0920a8fe796d", - "metadata": {}, - "source": [ - "The following cell uploads the `transpile_remote.py` file as a Qiskit Serverless program under the name `transpile_remote_serverless`." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "c467b63b-364f-4bdd-8e65-7a0c013e5d2c", - "metadata": {}, - "outputs": [], - "source": [ - "serverless = QiskitServerless()\n", - "\n", - "transpile_remote_demo = QiskitFunction(\n", - " title=\"transpile_remote_serverless\",\n", - " entrypoint=\"transpile_remote.py\",\n", - " working_dir=\"./source_files/\",\n", - ")\n", - "serverless.upload(transpile_remote_demo)\n", - "transpile_remote_serverless = serverless.load(\"transpile_remote_serverless\")" - ] - }, - { - "cell_type": "markdown", - "id": "1571a9ab-aeff-4033-b33f-0c4c6e760808", - "metadata": {}, - "source": [ - "Generate 20 different seeds to represent 20 different layout trials." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "6bc1561c-e057-4247-9425-c29dfe7cc555", - "metadata": {}, - "outputs": [], - "source": [ - "num_seeds = 20 # represents the different layout trials\n", - "seed_list = [seed + i for i in range(num_seeds)]" - ] - }, - { - "cell_type": "markdown", - "id": "d2a3f146-49e9-468a-9793-2559a9182e1b", - "metadata": {}, - "source": [ - "Run the uploaded program and pass inputs for lookahead heuristic." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "95bad790-86e8-4cca-bfd5-b57b1e6a26c1", - "metadata": {}, - "outputs": [], - "source": [ - "job_lookahead = transpile_remote_serverless.run(\n", - " circuit=qc,\n", - " backend_name=backend.name,\n", - " optimization_level=3,\n", - " seed_list=seed_list,\n", - " swap_trials=swap_trials,\n", - " heuristic=\"lookahead\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "51409259-e359-4b20-90f6-e5c432c3d01a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'15767dfc-e71d-4720-94d6-9212f72334c2'" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "job_lookahead.job_id" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "61049219-0189-4d0c-b717-3e74a1dd7455", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'QUEUED'" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "job_lookahead.status()" - ] - }, - { - "cell_type": "markdown", - "id": "1254e7f4-f2b7-47a1-8373-36dfc4ef8752", - "metadata": {}, - "source": [ - "Receive the logs and results from the serverless runtime." + "operators = [SparsePauliOp(op) for op in operator_strings]" ] }, { "cell_type": "code", - "execution_count": 21, - "id": "46504d93-a0c8-4077-8075-07271f6c93b0", + "execution_count": 8, + "id": "43ec98c6-f4c6-4584-8ba0-edfb4e99f04a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "No logs yet.\n" + "basic:\n", + " 2Q depth — min: 524, mean: 570.5, std: 39.9\n", + " size — min: 3821, mean: 4230.0, std: 358.1\n", + " best seed: 51 (2Q depth=524, size=3853)\n", + "decay:\n", + " 2Q depth — min: 387, mean: 436.4, std: 41.7\n", + " size — min: 2704, mean: 3186.4, std: 457.2\n", + " best seed: 45 (2Q depth=387, size=2786)\n", + "lookahead:\n", + " 2Q depth — min: 364, mean: 424.6, std: 36.5\n", + " size — min: 2335, mean: 3017.2, std: 388.3\n", + " best seed: 51 (2Q depth=364, size=2485)\n" ] } ], "source": [ - "logs_lookahead = job_lookahead.logs()\n", - "print(logs_lookahead)" - ] - }, - { - "cell_type": "markdown", - "id": "a1d4c23a-7f11-491b-b61c-1aadc7351df6", - "metadata": {}, - "source": [ - "Once a program is `DONE`, you can use `job.results()` to fetch the result stored in `save_result()`." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "61ce55f7-abec-458d-a0b8-f34d1e79f838", - "metadata": {}, - "outputs": [], - "source": [ - "# Run the job with lookahead heuristic\n", - "start_time = time.time()\n", - "results_lookahead = job_lookahead.result()\n", - "end_time = time.time()\n", - "\n", - "job_lookahead_time = end_time - start_time" - ] - }, - { - "cell_type": "markdown", - "id": "5c7d6447-2492-4b7d-83a7-62052c6c982a", - "metadata": {}, - "source": [ - "Now perform the same for decay heuristic." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "cc400305-3f34-46fe-95bf-fb672ae00954", - "metadata": {}, - "outputs": [], - "source": [ - "job_decay = transpile_remote_serverless.run(\n", - " circuit=qc,\n", - " backend_name=backend.name,\n", - " optimization_level=3,\n", - " seed_list=seed_list,\n", - " swap_trials=swap_trials,\n", - " heuristic=\"decay\",\n", - ")" + "# -------------------------Step 2-------------------------\n", + "\n", + "num_seeds = 10\n", + "seed_list = [seed + i for i in range(num_seeds)]\n", + "swap_trials = 200\n", + "\n", + "heuristic_results = {}\n", + "\n", + "for heuristic in [\"basic\", \"decay\", \"lookahead\"]:\n", + " trials = []\n", + " for s in seed_list:\n", + " sr = SabreSwap(\n", + " coupling_map=cmap, heuristic=heuristic, trials=swap_trials, seed=s\n", + " )\n", + " sl = SabreLayout(coupling_map=cmap, routing_pass=sr, seed=s)\n", + " pm = generate_preset_pass_manager(\n", + " optimization_level=3, backend=backend, seed_transpiler=s\n", + " )\n", + " pm.layout.replace(index=2, passes=sl)\n", + " pm.routing.replace(index=1, passes=sr)\n", + "\n", + " t0 = time.time()\n", + " tqc = pm.run(qc)\n", + " elapsed = time.time() - t0\n", + " depth = tqc.depth(lambda x: x.operation.num_qubits == 2)\n", + " size = tqc.size()\n", + " trials.append(\n", + " {\n", + " \"tqc\": tqc,\n", + " \"depth\": depth,\n", + " \"size\": size,\n", + " \"time\": elapsed,\n", + " \"seed\": s,\n", + " }\n", + " )\n", + "\n", + " heuristic_results[heuristic] = trials\n", + " depths = [t[\"depth\"] for t in trials]\n", + " sizes = [t[\"size\"] for t in trials]\n", + " best = min(trials, key=lambda t: t[\"depth\"])\n", + " print(f\"{heuristic}:\")\n", + " print(\n", + " f\" 2Q depth: min: {min(depths)}, mean: {np.mean(depths):.1f}, std: {np.std(depths):.1f}\"\n", + " )\n", + " print(\n", + " f\" size : min: {min(sizes)}, mean: {np.mean(sizes):.1f}, std: {np.std(sizes):.1f}\"\n", + " )\n", + " print(\n", + " f\" best seed: {best['seed']} (2Q depth={best['depth']}, size={best['size']})\"\n", + " )" ] }, { "cell_type": "code", - "execution_count": 34, - "id": "da60e3e8-a65e-456c-988b-65ba6d16f65a", + "execution_count": 9, + "id": "eead9bd2-17e0-4f5b-80bc-eb9b30af052e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'00418c76-d6ec-4bd8-9f70-05d0fa14d4eb'" + "\"Output" ] }, - "execution_count": 34, "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "job_decay.job_id" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "b32d4bd0-6ffa-42b2-a827-e606cc79791d", - "metadata": {}, - "outputs": [ + "output_type": "display_data" + }, { "name": "stdout", "output_type": "stream", "text": [ - "No logs yet.\n" + "basic: best 2Q depth=524, size=3853 (seed=51)\n", + "decay: best 2Q depth=387, size=2786 (seed=45)\n", + "lookahead: best 2Q depth=364, size=2485 (seed=51)\n" ] } ], "source": [ - "logs_decay = job_decay.logs()\n", - "print(logs_decay)" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "2552cd11-8283-47c5-86c9-58541ee31a12", - "metadata": {}, - "outputs": [], - "source": [ - "# Run the job with the decay heuristic\n", - "start_time = time.time()\n", - "results_decay = job_decay.result()\n", - "end_time = time.time()\n", + "hw_colors = {\"basic\": \"#ff7f0e\", \"decay\": \"#d62728\", \"lookahead\": \"#1f77b4\"}\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5))\n", + "\n", + "for heuristic in [\"basic\", \"decay\", \"lookahead\"]:\n", + " trials = heuristic_results[heuristic]\n", + " depths = [t[\"depth\"] for t in trials]\n", + " sizes = [t[\"size\"] for t in trials]\n", + " seeds = [t[\"seed\"] for t in trials]\n", + " color = hw_colors[heuristic]\n", + "\n", + " ax1.scatter(\n", + " seeds,\n", + " depths,\n", + " label=heuristic,\n", + " color=color,\n", + " alpha=0.8,\n", + " edgecolor=\"k\",\n", + " s=60,\n", + " )\n", + " ax1.axhline(np.mean(depths), color=color, linestyle=\"--\", alpha=0.5)\n", + "\n", + " ax2.scatter(\n", + " seeds,\n", + " sizes,\n", + " label=heuristic,\n", + " color=color,\n", + " alpha=0.8,\n", + " edgecolor=\"k\",\n", + " s=60,\n", + " )\n", + " ax2.axhline(np.mean(sizes), color=color, linestyle=\"--\", alpha=0.5)\n", + "\n", + "ax1.set_xlabel(\"Seed\", fontsize=11)\n", + "ax1.set_ylabel(\"2Q Depth\", fontsize=11)\n", + "ax1.set_title(\"Two-Qubit Gate Depth per Seed\", fontsize=13)\n", + "ax1.legend(fontsize=10)\n", + "ax1.grid(alpha=0.3)\n", + "\n", + "ax2.set_xlabel(\"Seed\", fontsize=11)\n", + "ax2.set_ylabel(\"Gate Count\", fontsize=11)\n", + "ax2.set_title(\"Circuit Size per Seed\", fontsize=13)\n", + "ax2.legend(fontsize=10)\n", + "ax2.grid(alpha=0.3)\n", + "\n", + "plt.suptitle(\n", + " \"Transpilation variability across seeds: basic vs. decay vs. lookahead\",\n", + " fontsize=14,\n", + " fontweight=\"bold\",\n", + " y=1.02,\n", + ")\n", + "plt.tight_layout()\n", + "plt.show()\n", "\n", - "job_decay_time = end_time - start_time" + "# Summary comparison\n", + "for heuristic in [\"basic\", \"decay\", \"lookahead\"]:\n", + " best = min(heuristic_results[heuristic], key=lambda t: t[\"depth\"])\n", + " print(\n", + " f\"{heuristic}: best 2Q depth={best['depth']}, size={best['size']} (seed={best['seed']})\"\n", + " )" ] }, { "cell_type": "code", - "execution_count": 37, - "id": "fa620c66-c6bd-4e8e-9fe1-46fd614b24fc", + "execution_count": null, + "id": "5ad47245-41d0-4d90-ba94-dda4cd63705d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "=== Total Transpilation Time (Serial Execution) ===\n", - "Decay Heuristic : 112.37 seconds\n", - "Lookahead Heuristic: 85.37 seconds\n", - "\n", - "=== Serverless Job Time (Parallel Execution) ===\n", - "Decay Heuristic : 5.72 seconds\n", - "Lookahead Heuristic: 5.85 seconds\n", - "\n", - "=== Average Time Per Transpilation ===\n", - "Decay Heuristic (Serial) : 5.62 seconds\n", - "Decay Heuristic (Serverless): 0.29 seconds\n", - "Lookahead Heuristic (Serial) : 4.27 seconds\n", - "Lookahead Heuristic (Serverless): 0.29 seconds\n", - "\n", - "=== Serverless Improvement ===\n", - "Decay Heuristic : 94.91%\n", - "Lookahead Heuristic: 93.14%\n" + "Best basic: 2Q depth=524, size=3853\n", + "Best decay: 2Q depth=387, size=2786\n", + "Best lookahead: 2Q depth=364, size=2485\n", + "basic job: d7c23795a5qc73do4s0g\n", + "decay job: d7c237j0g7hs73dq7rjg\n", + "lookahead job: d7c237p5a5qc73do4s1g\n", + "basic job done\n", + "decay job done\n", + "lookahead job done\n" ] } ], "source": [ - "# Extract transpilation times\n", - "transpile_times_decay = results_decay[\"transpile_times\"]\n", - "transpile_times_lookahead = results_lookahead[\"transpile_times\"]\n", - "\n", - "# Calculate total transpilation time for serial execution\n", - "total_transpile_time_decay = sum(transpile_times_decay)\n", - "total_transpile_time_lookahead = sum(transpile_times_lookahead)\n", - "\n", - "# Print total transpilation time\n", - "print(\"=== Total Transpilation Time (Serial Execution) ===\")\n", - "print(f\"Decay Heuristic : {total_transpile_time_decay:.2f} seconds\")\n", - "print(f\"Lookahead Heuristic: {total_transpile_time_lookahead:.2f} seconds\")\n", - "\n", - "# Print serverless job time (parallel execution)\n", - "print(\"\\n=== Serverless Job Time (Parallel Execution) ===\")\n", - "print(f\"Decay Heuristic : {job_decay_time:.2f} seconds\")\n", - "print(f\"Lookahead Heuristic: {job_lookahead_time:.2f} seconds\")\n", - "\n", - "# Calculate and print average runtime per transpilation\n", - "avg_transpile_time_decay = total_transpile_time_decay / num_seeds\n", - "avg_transpile_time_lookahead = total_transpile_time_lookahead / num_seeds\n", - "avg_job_time_decay = job_decay_time / num_seeds\n", - "avg_job_time_lookahead = job_lookahead_time / num_seeds\n", - "\n", - "print(\"\\n=== Average Time Per Transpilation ===\")\n", - "print(f\"Decay Heuristic (Serial) : {avg_transpile_time_decay:.2f} seconds\")\n", - "print(f\"Decay Heuristic (Serverless): {avg_job_time_decay:.2f} seconds\")\n", - "print(\n", - " f\"Lookahead Heuristic (Serial) : {avg_transpile_time_lookahead:.2f} seconds\"\n", - ")\n", - "print(\n", - " f\"Lookahead Heuristic (Serverless): {avg_job_time_lookahead:.2f} seconds\"\n", - ")\n", + "# -------------------------Step 3: Execute on hardware-------------------------\n", "\n", - "# Calculate and print serverless improvement percentage\n", - "decay_improvement_percentage = (\n", - " (total_transpile_time_decay - job_decay_time) / total_transpile_time_decay\n", - ") * 100\n", - "lookahead_improvement_percentage = (\n", - " (total_transpile_time_lookahead - job_lookahead_time)\n", - " / total_transpile_time_lookahead\n", - ") * 100\n", - "\n", - "print(\"\\n=== Serverless Improvement ===\")\n", - "print(f\"Decay Heuristic : {decay_improvement_percentage:.2f}%\")\n", - "print(f\"Lookahead Heuristic: {lookahead_improvement_percentage:.2f}%\")" - ] - }, - { - "cell_type": "markdown", - "id": "5296f4b5-1ac7-497e-979f-ea5eaea7448a", - "metadata": {}, - "source": [ - "These results demonstrate the substantial efficiency gains from using serverless execution for quantum circuit transpilation. Compared to serial execution, serverless execution dramatically reduces overall runtime for both the `decay` and `lookahead` heuristics by parallelizing independent transpilation trials. While serial execution reflects the full cumulative cost of exploring multiple layout trials, the serverless job times highlight how parallel execution collapses this cost into a much shorter wall-clock time. As a result, the effective time per transpilation is reduced to a small fraction of that required in the serial setting, largely independent of the heuristic used. This capability is particularly important for optimizing SABRE to its fullest potential. Many of SABRE’s strongest performance gains come from increasing the number of layout and routing trials, which can be prohibitively expensive when executed sequentially. Serverless execution removes this bottleneck, enabling large-scale parameter sweeps and deeper exploration of heuristic configurations with minimal overhead.\n", + "best_circuits = {}\n", + "for heuristic in [\"basic\", \"decay\", \"lookahead\"]:\n", + " best_circuits[heuristic] = min(\n", + " heuristic_results[heuristic], key=lambda t: t[\"depth\"]\n", + " )\n", + " b = best_circuits[heuristic]\n", + " print(f\"Best {heuristic}: 2Q depth={b['depth']}, size={b['size']}\")\n", "\n", - "Overall, these findings show that serverless execution is key to scaling SABRE optimization, making aggressive experimentation and refinement practical compared to serial execution." - ] - }, - { - "cell_type": "markdown", - "id": "e4f41118-cfb9-4aa3-8aba-201ceadd2195", - "metadata": {}, - "source": [ - "Obtain the results from the serverless runtime and compare the results of the lookahead and decay heuristics. We will compare the sizes and depths." + "options = EstimatorOptions()\n", + "options.resilience_level = 2\n", + "options.dynamical_decoupling.enable = True\n", + "options.dynamical_decoupling.sequence_type = \"XY4\"\n", + "estimator = Estimator(backend, options=options)\n", + "\n", + "hw_jobs = {}\n", + "hw_ops = {}\n", + "for heuristic, best in best_circuits.items():\n", + " hw_ops[heuristic] = [\n", + " op.apply_layout(best[\"tqc\"].layout) for op in operators\n", + " ]\n", + " hw_jobs[heuristic] = estimator.run([(best[\"tqc\"], hw_ops[heuristic])])\n", + " print(f\"{heuristic} job: {hw_jobs[heuristic].job_id()}\")\n", + "estimator.options.environment.job_tags = [\"TUT_TOWS\"]\n", + "\n", + "hw_results = {}\n", + "for heuristic, job in hw_jobs.items():\n", + " hw_results[heuristic] = job.result()[0]\n", + " print(f\"{heuristic} job done\")" ] }, { "cell_type": "code", - "execution_count": 38, - "id": "4cf9588b-8ea6-4761-b544-14bef8f0be85", + "execution_count": 11, + "id": "0280b0b9-6320-43e5-8396-f82f9e718319", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Output" + "\"Output" ] }, "metadata": {}, "output_type": "display_data" }, - { - "data": { - "text/plain": [ - "\"Output" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Extract sizes and depths\n", - "sizes_lookahead = [\n", - " circuit.size() for circuit in results_lookahead[\"transpiled_circuits\"]\n", - "]\n", - "depths_lookahead = [\n", - " circuit.depth(lambda x: x.operation.num_qubits == 2)\n", - " for circuit in results_lookahead[\"transpiled_circuits\"]\n", - "]\n", - "sizes_decay = [\n", - " circuit.size() for circuit in results_decay[\"transpiled_circuits\"]\n", - "]\n", - "depths_decay = [\n", - " circuit.depth(lambda x: x.operation.num_qubits == 2)\n", - " for circuit in results_decay[\"transpiled_circuits\"]\n", - "]\n", - "\n", - "\n", - "def create_scatterplot(x, y1, y2, xlabel, ylabel, title, labels, colors):\n", - " plt.figure(figsize=(8, 5))\n", - " plt.scatter(\n", - " x, y1, label=labels[0], color=colors[0], alpha=0.8, edgecolor=\"k\"\n", - " )\n", - " plt.scatter(\n", - " x, y2, label=labels[1], color=colors[1], alpha=0.8, edgecolor=\"k\"\n", - " )\n", - " plt.xlabel(xlabel, fontsize=12)\n", - " plt.ylabel(ylabel, fontsize=12)\n", - " plt.title(title, fontsize=14)\n", - " plt.legend(fontsize=10)\n", - " plt.grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", - " plt.tight_layout()\n", - " plt.show()\n", - "\n", - "\n", - "create_scatterplot(\n", - " seed_list,\n", - " sizes_lookahead,\n", - " sizes_decay,\n", - " \"Seed\",\n", - " \"Size\",\n", - " \"Circuit Size\",\n", - " [\"lookahead\", \"Decay\"],\n", - " [\"blue\", \"red\"],\n", - ")\n", - "create_scatterplot(\n", - " seed_list,\n", - " depths_lookahead,\n", - " depths_decay,\n", - " \"Seed\",\n", - " \"Depth\",\n", - " \"Circuit Depth\",\n", - " [\"lookahead\", \"Decay\"],\n", - " [\"blue\", \"red\"],\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "9f905f0d-f439-4a7c-9006-be7f292713fc", - "metadata": {}, - "source": [ - "Each point in the scatter plots above represents a layout trial, with the x-axis indicating the circuit depth and the y-axis indicating the circuit size. The results reveal that the lookahead heuristic generally outperforms the decay heuristic in minimizing circuit depth and circuit size. In practical applications, the goal is to identify the optimal layout trial for your chosen heuristic, whether prioritizing depth or size. This can be achieved by selecting the trial with the lowest value for the desired metric. Importantly, increasing the number of layout trials improves the chances of achieving a better result in terms of size or depth, but it comes at the cost of higher computational overhead." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "e0db89b9-171a-473b-bcb4-19a65b75155c", - "metadata": {}, - "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Lookahead: Min Depth 399 Min Size 2452\n", - "Decay: Min Depth 415 Min Size 2611\n" + "\n", + "Mean fidelity:\n", + " basic: 0.0247\n", + " decay: 0.3731\n", + " lookahead: 0.2837\n" ] } ], "source": [ - "min_depth_lookahead = min(depths_lookahead)\n", - "min_depth_decay = min(depths_decay)\n", - "min_size_lookahead = min(sizes_lookahead)\n", - "min_size_decay = min(sizes_decay)\n", - "print(\n", - " \"Lookahead: Min Depth\",\n", - " min_depth_lookahead,\n", - " \"Min Size\",\n", - " min_size_lookahead,\n", + "# -------------------------Step 4: Post-process-------------------------\n", + "\n", + "data = list(range(1, len(operators) + 1))\n", + "hw_markers = {\"basic\": \"D\", \"decay\": \"o\", \"lookahead\": \"s\"}\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(\n", + " 1, 2, figsize=(14, 5), gridspec_kw={\"width_ratios\": [2.5, 1]}\n", + ")\n", + "\n", + "# Left: correlations vs distance\n", + "for heuristic in [\"basic\", \"decay\", \"lookahead\"]:\n", + " evs = list(hw_results[heuristic].data.evs)\n", + " b = best_circuits[heuristic]\n", + " ax1.plot(\n", + " data,\n", + " evs,\n", + " marker=hw_markers[heuristic],\n", + " color=hw_colors[heuristic],\n", + " linewidth=2,\n", + " label=f\"{heuristic} (2Q depth={b['depth']}, size={b['size']})\",\n", + " markersize=4,\n", + " )\n", + "\n", + "ax1.set_xlabel(\"Distance between qubits $i$\", fontsize=11)\n", + "ax1.set_ylabel(r\"$\\langle Z_0 Z_i \\rangle$\", fontsize=11)\n", + "ax1.set_title(\n", + " \"Entanglement correlations vs. qubit distance (hardware)\", fontsize=12\n", + ")\n", + "ax1.legend(fontsize=9)\n", + "ax1.grid(alpha=0.3)\n", + "\n", + "# Right: mean fidelity bar chart\n", + "hw_heuristics = [\"basic\", \"decay\", \"lookahead\"]\n", + "hw_means = [np.mean(list(hw_results[h].data.evs)) for h in hw_heuristics]\n", + "hw_bar_colors = [hw_colors[h] for h in hw_heuristics]\n", + "x_bar = np.arange(len(hw_heuristics))\n", + "bars = ax2.bar(x_bar, hw_means, color=hw_bar_colors)\n", + "ax2.set_ylabel(r\"Mean $\\langle Z_0 Z_i \\rangle$\", fontsize=11)\n", + "ax2.set_title(\"Average fidelity\", fontsize=13)\n", + "y_range = (\n", + " max(hw_means) - min(hw_means) if max(hw_means) != min(hw_means) else 0.01\n", ")\n", - "print(\"Decay: Min Depth\", min_depth_decay, \"Min Size\", min_size_decay)" + "ax2.set_ylim(min(hw_means) - y_range * 0.8, max(hw_means) + y_range * 0.8)\n", + "for bar, val in zip(bars, hw_means):\n", + " ax2.text(\n", + " bar.get_x() + bar.get_width() / 2,\n", + " bar.get_height() + y_range * 0.08,\n", + " f\"{val:.4f}\",\n", + " ha=\"center\",\n", + " va=\"bottom\",\n", + " fontsize=11,\n", + " fontweight=\"bold\",\n", + " )\n", + "ax2.set_xticks(x_bar)\n", + "ax2.set_xticklabels(hw_heuristics, fontsize=10)\n", + "ax2.grid(axis=\"y\", linestyle=\"--\", alpha=0.5)\n", + "\n", + "fig.tight_layout()\n", + "plt.show()\n", + "\n", + "print(\"\\nMean fidelity:\")\n", + "for h, m in zip(hw_heuristics, hw_means):\n", + " print(f\" {h}: {m:.4f}\")" ] }, { "cell_type": "markdown", - "id": "762c6b28-a968-4d0d-8a06-7e5a19197d0d", + "id": "151e5fe9-872a-4b89-92f9-85bb883de17b", "metadata": {}, "source": [ - "In our initial comparison using a single layout trial, the lookahead heuristic showed slightly better performance in both circuit depth and size. By extending this study to multiple layout trials using `QiskitServerless`, we were able to explore a much broader space of SABRE initializations, enabling a more representative comparison between heuristics.\n", + "### Analysis\n", "\n", - "From the scatter plots and the best observed results, it is clear that performance varies significantly with the random seed used by SABRE. Both heuristics exhibit a wide spread in circuit depth and size across seeds, indicating that a single run is often insufficient to capture near-optimal results. This variability highlights the importance of running many trials with different seeds when aiming to minimize depth and/or gate count. Across the full set of trials, both the `lookahead` and `decay` heuristics were capable of producing competitive results. In some cases, the `decay` heuristic matched or even outperformed `lookahead` for specific seeds. However, for this particular circuit, the best overall results were obtained using the lookahead heuristic, albeit by a modest margin. This suggests that while lookahead provided the strongest outcome here, its advantage over decay is not absolute.\n", + "The scatter plots show significant variability across seeds for all three heuristics, which underscores the importance of running multiple layout trials rather than relying on a single transpilation.\n", "\n", - "Overall, these results reinforce two key points. First, leveraging many seeds is essential for extracting the best possible performance from SABRE, regardless of the heuristic used. Second, while heuristic choice matters, circuit structure plays a dominant role, and the relative performance of `lookahead` and `decay` may differ for other circuits. As such, large-scale, multi-seed experimentation is critical for robust and effective quantum circuit transpilation." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "42343aca-1327-4ac8-bbd0-880aa916a091", - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# This cell is hidden from users, it cleans up the `source_files` directory\n", - "from pathlib import Path\n", + "From the transpilation results, both the `decay` and `lookahead` heuristics consistently outperform `basic` by a wide margin in terms of 2Q depth and circuit size. The `basic` heuristic, while fast, uses a simple greedy strategy that often leads to substantially deeper circuits. For this type of star-topology GHZ circuit, `lookahead` tends to produce the lowest 2Q depth and gate count overall, since its forward-looking cost function is well suited to circuits with long-range connectivity patterns.\n", + "\n", + "However, lower 2Q depth and gate count do not always translate directly to higher fidelity. In this example, `decay` achieved a higher average fidelity than `lookahead` despite having a slightly higher 2Q depth. This illustrates that fidelity depends on more than just depth and gate count. The specific circuit structure, how gates are arranged relative to the device's noise profile, and which physical qubits are used all play a role. Notably, while `decay` had a higher average fidelity overall, `lookahead` consistently achieved better fidelity at longer distances (beyond qubit distance ~60), where the impact of circuit depth becomes more dominant.\n", "\n", - "Path(\"source_files/transpile_remote.py\").unlink()\n", - "Path(\"source_files\").rmdir()" + "**Key takeaways:**\n", + "- The `decay` and `lookahead` heuristics are substantially better than `basic` for non-trivial circuits. Always prefer one of the two for production workloads.\n", + "- The best heuristic depends on your circuit and hardware. Testing multiple heuristics with multiple seeds is the most reliable strategy.\n", + "- For even broader exploration of the layout space, consider parallelizing seed trials with [Qiskit Serverless](/docs/guides/serverless)." ] }, { "cell_type": "markdown", - "id": "b2c5e4ad-cc9f-4090-a513-164bc4a46b85", + "id": "65c2cebe-50b9-4304-9123-bf4cea7ecff6", "metadata": {}, "source": [ - "## Conclusion\n", - "\n", - "In this tutorial, we explored how to optimize large circuits using SABRE in Qiskit. We demonstrated how to configure the `SabreLayout` pass with different parameters to balance circuit quality and transpilation runtime. We also showed how to customize the routing heuristic in SABRE and use the `QiskitServerless`runtime to parallelize layout trials efficiently for when `SabreSwap` is involved. By adjusting these parameters and heuristics, you can optimize the layout and routing of large circuits, ensuring they are executed efficiently on quantum hardware." + "## Next steps\n", + "If you found this work interesting, you might be interested in the following material:\n", + "\n", + "- [SabreLayout API reference](/docs/api/qiskit/qiskit.transpiler.passes.SabreLayout): full parameter documentation\n", + "- [Write a custom transpiler pass](/docs/guides/custom-transpiler-pass): build your own transpilation logic\n", + "- [Transpiler plugins](/docs/guides/transpiler-plugins): extend Qiskit's transpilation pipeline with third-party passes\n", + "- [DAG representation](/docs/guides/DAG-representation): understand the directed acyclic graph used internally by the transpiler\n", + "" ] }, { "cell_type": "markdown", - "id": "b21ac273-966f-41c2-a54e-1bb76072b2fe", + "id": "42d1c053-1683-4c32-be1b-a36602207f74", "metadata": {}, "source": [ "## Tutorial survey\n", diff --git a/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/0280b0b9-6320-43e5-8396-f82f9e718319-0.avif b/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/0280b0b9-6320-43e5-8396-f82f9e718319-0.avif new file mode 100644 index 0000000000000000000000000000000000000000..430b721bf9f095c2a78f5c9e30c41f605a1dcb41 GIT binary patch literal 26319 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 R>uNseWkMr54Bi{*>yLsv#;5=Q literal 0 HcmV?d00001 diff --git a/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/4cf9588b-8ea6-4761-b544-14bef8f0be85-0.avif b/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/4cf9588b-8ea6-4761-b544-14bef8f0be85-0.avif deleted file mode 100644 index 6c2bd6b4988caedc40a68db563f52dba59324aa3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12141 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 YlrYJsZF}V|i9StRq}Kvc$w))=f1h9k<^TWy diff --git a/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/4cf9588b-8ea6-4761-b544-14bef8f0be85-1.avif b/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/4cf9588b-8ea6-4761-b544-14bef8f0be85-1.avif deleted file mode 100644 index be637d9785b47dc3f4e10c02e92c3480c499d24b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11841 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 diff --git a/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/818a8997-d2c7-4661-a6ea-f58eac376bf8-0.avif b/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/818a8997-d2c7-4661-a6ea-f58eac376bf8-0.avif deleted file mode 100644 index de3bd8c5500613654c150345e7b582100c845102..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7951 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 diff --git a/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/a6dac5ed-a963-458a-ada1-89c915f036e0-0.avif b/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/a6dac5ed-a963-458a-ada1-89c915f036e0-0.avif new file mode 100644 index 0000000000000000000000000000000000000000..2a054dfa5b1116583da6bf6ff4181a715c186702 GIT binary patch literal 16693 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

fgR(`G0 zcTrfGeaxmL%da;MAk@T`JzFCCQRHCoZ0f~3ii0NeYCD~8Qeoz}Tf>Q!4c%nLY05mW z0Evy{Q>+@>1iy1-j!bhO96Tts2hh(LiK)Ol<;vd|gVt}yjZ&`{8(z4!u<=4%Y6~D* z{0bC>g1O5+ZY;PeKO%T_Lr{!w{FJ$-*QNn+@-fdn_eiY)zSG3CrTx(jUQ4?5Soiz+|=b)1N+jq5PGN&9=lc}8lE-M>4 z4Y$+nnG#q6YI}OB&2mm?o-($#T%zV1-f6>;W$w$@!H-Tj;BELQU6A!ScBg`Y`E{F- z4QD+MlMslhINjcLUS+BacgS>}>o3hcx;FFiM@7R(G&G3`hI2X>)pcSLqOZ3Vsdrx3 zUc=momUW9DF|uIu&qyF`mvwR+yN`IU*o4yq1+#dm(?Lk{ehR_XGOAonBEb;Cl|-dc zgI%d0E2ty4r3I)TpIlta@gz>7E(P*qx(-7{YCn^b*KcuGaZUR(ZO~vggfYIfxNP_+ zQ*p*R`wGp{e!H;|LoV0UV4CP|@(c~KO<8-0bBycYuoVo8gNs(eqPdsr8QA&ms=(&{v5hGOG91~IOOu}yMO%&tYqdvRxQjm$_$@FsSW|m z&ic3u7(ll#onuQnP1t5NIZW6(+Zx&lUXJ&Oc_J$0cyN!#WGmVR(lwbdKWTQGa`f#` z0%#t8y6a!Zg&xfH4&6Q>`p)w9o=R>js@XIHnM4>?_JJKvO1JF9)zQhtb27&UZ#{U_ zEUkk5q~jwcj1X5j2Am0oXti@Eh6WzyX+Jbn+~xeHW|Xhz=I?J&no~-gt;7GfY5}nn z)9bC3vW!+;oTVLm*72A&&lEcIFG3-&W}obinLmKL>e<1&>RTO*?0_5%hc6!l?ru=e zn;Wq1#0|UmTp!PTndv(xk$K{8-Qd02r&Zgo=H7^(d;EV7%gy_*v+Q1^Iw@Q6+>?I! Gx*q`KZ{HXI literal 0 HcmV?d00001 diff --git a/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/bc6cb36f-4bf2-4275-baf5-9557fcba520a-0.avif b/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/bc6cb36f-4bf2-4275-baf5-9557fcba520a-0.avif deleted file mode 100644 index 24dcd16ac1773e48da09df19c35d6b895d731b42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17658 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 hK(-juI(+k-zzNwIumeXJO3a4KMfDC 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 T9U(p3x&a!XXE(3}8MgliFN5Jc literal 0 HcmV?d00001 diff --git a/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/eead9bd2-17e0-4f5b-80bc-eb9b30af052e-0.avif b/public/docs/images/tutorials/transpilation-optimizations-with-sabre/extracted-outputs/eead9bd2-17e0-4f5b-80bc-eb9b30af052e-0.avif new file mode 100644 index 0000000000000000000000000000000000000000..8f262afca284a8c2e6b35486f54c9a5b7998f8dc GIT binary patch literal 15367 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 ZLyM&v2)8y&F<*9{=LD literal 0 HcmV?d00001 From 6e917f386920f24104e8934a0fa27009f542ce07 Mon Sep 17 00:00:00 2001 From: Henry Zou Date: Fri, 10 Apr 2026 06:35:39 -0400 Subject: [PATCH 2/2] npm run check --- ...anspilation-optimizations-with-sabre.ipynb | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/tutorials/transpilation-optimizations-with-sabre.ipynb b/docs/tutorials/transpilation-optimizations-with-sabre.ipynb index 97ed5ed9d0b..718a3a2b762 100644 --- a/docs/tutorials/transpilation-optimizations-with-sabre.ipynb +++ b/docs/tutorials/transpilation-optimizations-with-sabre.ipynb @@ -11,7 +11,7 @@ "---\n", "\n", "\n", - "{/* cspell:ignore ylabel xlabel fontsize sharex edgecolor */}\n", + "{/* cspell:ignore ylabel xlabel fontsize sharex edgecolor, fontweight, elinewidth, ecolor */}\n", "\n", "# Transpilation Optimizations with SABRE\n", "*Usage estimate: 1 minute on a Heron r2 processor. (NOTE: This is an estimate only. Your runtime may vary.)*" @@ -30,9 +30,9 @@ "\n", "## Prerequisites\n", "We suggest that you are familiar with the following topics before going through this tutorial:\n", - "- [Transpile circuits](/docs/guides/transpile): overview of transpilation in Qiskit\n", - "- [Transpiler stages](/docs/guides/transpiler-stages): layout and routing stages\n", - "- [Configure preset pass managers](/docs/guides/configure-preset-pass-managers): customizing optimization levels\n", + "- [Transpile circuits](https://quantum.cloud.ibm.com/docs/en/guides/transpile): overview of transpilation in Qiskit\n", + "- [Transpiler stages](https://quantum.cloud.ibm.com/docs/en/guides/transpiler-stages): layout and routing stages\n", + "- [Configure preset pass managers](https://quantum.cloud.ibm.com/docs/en/guides/transpile-with-pass-managers): customizing optimization levels\n", "\n", "## Background\n", "\n", @@ -51,7 +51,7 @@ "## Requirements\n", "\n", "Before starting this tutorial, be sure you have the following installed:\n", - "- Qiskit SDK v2.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n", + "- Qiskit SDK v2.0 or later, with [visualization](https://quantum.cloud.ibm.com/docs/en/api/qiskit/visualization) support\n", "- Qiskit Runtime v0.22 or later (`pip install qiskit-ibm-runtime`)\n", "- Qiskit Aer (`pip install qiskit-aer`)" ] @@ -625,16 +625,16 @@ "output_type": "stream", "text": [ "basic:\n", - " 2Q depth — min: 524, mean: 570.5, std: 39.9\n", - " size — min: 3821, mean: 4230.0, std: 358.1\n", + " 2Q depth \u2014 min: 524, mean: 570.5, std: 39.9\n", + " size \u2014 min: 3821, mean: 4230.0, std: 358.1\n", " best seed: 51 (2Q depth=524, size=3853)\n", "decay:\n", - " 2Q depth — min: 387, mean: 436.4, std: 41.7\n", - " size — min: 2704, mean: 3186.4, std: 457.2\n", + " 2Q depth \u2014 min: 387, mean: 436.4, std: 41.7\n", + " size \u2014 min: 2704, mean: 3186.4, std: 457.2\n", " best seed: 45 (2Q depth=387, size=2786)\n", "lookahead:\n", - " 2Q depth — min: 364, mean: 424.6, std: 36.5\n", - " size — min: 2335, mean: 3017.2, std: 388.3\n", + " 2Q depth \u2014 min: 364, mean: 424.6, std: 36.5\n", + " size \u2014 min: 2335, mean: 3017.2, std: 388.3\n", " best seed: 51 (2Q depth=364, size=2485)\n" ] } @@ -944,7 +944,7 @@ "**Key takeaways:**\n", "- The `decay` and `lookahead` heuristics are substantially better than `basic` for non-trivial circuits. Always prefer one of the two for production workloads.\n", "- The best heuristic depends on your circuit and hardware. Testing multiple heuristics with multiple seeds is the most reliable strategy.\n", - "- For even broader exploration of the layout space, consider parallelizing seed trials with [Qiskit Serverless](/docs/guides/serverless)." + "- For even broader exploration of the layout space, consider parallelizing seed trials with [Qiskit Serverless](https://quantum.cloud.ibm.com/docs/en/guides/serverless)." ] }, { @@ -955,10 +955,10 @@ "## Next steps\n", "If you found this work interesting, you might be interested in the following material:\n", "\n", - "- [SabreLayout API reference](/docs/api/qiskit/qiskit.transpiler.passes.SabreLayout): full parameter documentation\n", - "- [Write a custom transpiler pass](/docs/guides/custom-transpiler-pass): build your own transpilation logic\n", - "- [Transpiler plugins](/docs/guides/transpiler-plugins): extend Qiskit's transpilation pipeline with third-party passes\n", - "- [DAG representation](/docs/guides/DAG-representation): understand the directed acyclic graph used internally by the transpiler\n", + "- [SabreLayout API reference](https://quantum.cloud.ibm.com/docs/en/api/qiskit/qiskit.transpiler.passes.SabreLayout): full parameter documentation\n", + "- [Write a custom transpiler pass](https://quantum.cloud.ibm.com/docs/en/guides/custom-transpiler-pass): build your own transpilation logic\n", + "- [Transpiler plugins](https://quantum.cloud.ibm.com/docs/en/guides/transpiler-plugins): extend Qiskit's transpilation pipeline with third-party passes\n", + "- [DAG representation](https://quantum.cloud.ibm.com/docs/en/guides/DAG-representation): understand the directed acyclic graph used internally by the transpiler\n", "" ] },