microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
be82821236a00686b004bc7fe619ad16904f7997

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

samples/qre/3_building_your_own_models.ipynb

1135lines · modepreview

{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "226dfb5f",
   "metadata": {},
   "source": [
    "# Exploring Hypothetical Hardware\n",
    "\n",
    "The [previous notebooks](0_getting_started.ipynb) showed how to use the quantum\n",
    "resource estimator with built-in models like `GateBased`, `SurfaceCode`, and\n",
    "`Litinski19Factory`.  These models capture well-studied hardware assumptions,\n",
    "but what if your hardware doesn't match them?\n",
    "\n",
    "In this notebook we build **custom models** to answer three \"what if\" questions:\n",
    "\n",
    "- **Architecture model:** What if my qubits had different gate speeds and error rates?\n",
    "- **QEC ISA transform:** What if I had a QEC code with a higher threshold or lower overhead?\n",
    "- **Factory transform:** What if my magic state distillation protocol were different?\n",
    "\n",
    "Each model plugs into the estimator's layered architecture.  You implement a\n",
    "small Python class and the estimator takes care of the rest: enumerating\n",
    "configurations, pruning infeasible ones, and finding the Pareto-optimal results.\n",
    "\n",
    "We finish by composing all three custom layers into a full estimation stack and\n",
    "comparing it against the built-in models."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5dafb171",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// This file provides CodeMirror syntax highlighting for Q# magic cells\n// in classic Jupyter Notebooks. It does nothing in other (Jupyter Notebook 7,\n// VS Code, Azure Notebooks, etc.) environments.\n\n// Detect the prerequisites and do nothing if they don't exist.\nif (window.require && window.CodeMirror && window.Jupyter) {\n  // The simple mode plugin for CodeMirror is not loaded by default, so require it.\n  window.require([\"codemirror/addon/mode/simple\"], function defineMode() {\n    let rules = [\n      {\n        token: \"comment\",\n        regex: /(\\/\\/).*/,\n        beginWord: false,\n      },\n      {\n        token: \"string\",\n        regex: String.raw`^\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S])*(?:\\\"|$)`,\n        beginWord: false,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(namespace|open|as|operation|function|body|adjoint|newtype|controlled|internal)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(if|elif|else|repeat|until|fixup|for|in|return|fail|within|apply)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(Adjoint|Controlled|Adj|Ctl|is|self|auto|distribute|invert|intrinsic)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(let|set|use|borrow|mutable)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(not|and|or)\\b|(w/)`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(=)|(!)|(<)|(>)|(\\+)|(-)|(\\*)|(/)|(\\^)|(%)|(\\|)|(&&&)|(~~~)|(\\.\\.\\.)|(\\.\\.)|(\\?)`,\n        beginWord: false,\n      },\n      {\n        token: \"meta\",\n        regex: String.raw`(Int|BigInt|Double|Bool|Qubit|Pauli|Result|Range|String|Unit)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"atom\",\n        regex: String.raw`(true|false|Pauli(I|X|Y|Z)|One|Zero)\\b`,\n        beginWord: true,\n      },\n    ];\n    let simpleRules = [];\n    for (let rule of rules) {\n      simpleRules.push({\n        token: rule.token,\n        regex: new RegExp(rule.regex, \"g\"),\n        sol: rule.beginWord,\n      });\n      if (rule.beginWord) {\n        // Need an additional rule due to the fact that CodeMirror simple mode doesn't work with ^ token\n        simpleRules.push({\n          token: rule.token,\n          regex: new RegExp(String.raw`\\W` + rule.regex, \"g\"),\n          sol: false,\n        });\n      }\n    }\n\n    // Register the mode defined above with CodeMirror\n    window.CodeMirror.defineSimpleMode(\"qsharp\", { start: simpleRules });\n    window.CodeMirror.defineMIME(\"text/x-qsharp\", \"qsharp\");\n\n    // Tell Jupyter to associate %%qsharp magic cells with the qsharp mode\n    window.Jupyter.CodeCell.options_default.highlight_modes[\"qsharp\"] = {\n      reg: [/^%%qsharp/],\n    };\n\n    // Force re-highlighting of all cells the first time this code runs\n    for (const cell of window.Jupyter.notebook.get_cells()) {\n      cell.auto_highlight();\n    }\n  });\n}\n",
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from dataclasses import KW_ONLY, dataclass, field\n",
    "from math import ceil\n",
    "from typing import Generator\n",
    "\n",
    "import qdk\n",
    "from qdk.qre import (\n",
    "    Architecture,\n",
    "    ISAContext,\n",
    "    ConstraintBound,\n",
    "    ISA,\n",
    "    ISARequirements,\n",
    "    ISATransform,\n",
    "    LOGICAL,\n",
    "    PHYSICAL,\n",
    "    constraint,\n",
    "    estimate,\n",
    "    linear_function,\n",
    "    plot_estimates,\n",
    ")\n",
    "from qdk.qre.models import GateBased, SurfaceCode, Litinski19Factory\n",
    "from qdk.qre.application import QSharpApplication\n",
    "from qdk.qre.instruction_ids import (\n",
    "    H, S, S_DAG, T, T_DAG, CNOT, CZ, MEAS_X, MEAS_Y, MEAS_Z, LATTICE_SURGERY,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ed9261a",
   "metadata": {},
   "source": [
    "## Setup and baseline\n",
    "\n",
    "We start with a simple Q# program and a baseline estimation using the built-in\n",
    "models.  This gives us a reference point to compare against later."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ccd60531",
   "metadata": {
    "vscode": {
     "languageId": "qsharp"
    }
   },
   "outputs": [],
   "source": [
    "%%qsharp\n",
    "\n",
    "import Std.Arithmetic.*;\n",
    "import Std.Math.*;\n",
    "import Std.Convert.*;\n",
    "\n",
    "/// An 8-bit adder with single-qubit rotations.\n",
    "/// The rotations introduce T gates via synthesis, which exercises\n",
    "/// the magic state factory during resource estimation.\n",
    "operation AdderWithRotations() : Unit {\n",
    "    use a = Qubit[8];\n",
    "    use b = Qubit[8];\n",
    "    for i in 0..7 {\n",
    "        Ry(PI() / IntAsDouble(i + 2), a[i]);\n",
    "    }\n",
    "    RippleCarryCGIncByLE(a, b);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "41bfdcd6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>qubits</th>\n",
       "      <th>runtime</th>\n",
       "      <th>error</th>\n",
       "      <th>physical_compute_qubits</th>\n",
       "      <th>physical_factory_qubits</th>\n",
       "      <th>physical_memory_qubits</th>\n",
       "      <th>factories</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Built-in models</td>\n",
       "      <td>9567</td>\n",
       "      <td>0 days 00:00:00.000225</td>\n",
       "      <td>0.007312</td>\n",
       "      <td>3087</td>\n",
       "      <td>6480</td>\n",
       "      <td>0</td>\n",
       "      <td>8×T</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Built-in models</td>\n",
       "      <td>13221</td>\n",
       "      <td>0 days 00:00:00.000141</td>\n",
       "      <td>0.009416</td>\n",
       "      <td>1071</td>\n",
       "      <td>12150</td>\n",
       "      <td>0</td>\n",
       "      <td>15×T</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              name  qubits                runtime     error  \\\n",
       "0  Built-in models    9567 0 days 00:00:00.000225  0.007312   \n",
       "1  Built-in models   13221 0 days 00:00:00.000141  0.009416   \n",
       "\n",
       "   physical_compute_qubits  physical_factory_qubits  physical_memory_qubits  \\\n",
       "0                     3087                     6480                       0   \n",
       "1                     1071                    12150                       0   \n",
       "\n",
       "  factories  \n",
       "0       8×T  \n",
       "1      15×T  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "app = QSharpApplication(qdk.code.AdderWithRotations)\n",
    "\n",
    "# Baseline: built-in architecture, QEC, and factory\n",
    "baseline_arch = GateBased(error_rate=1e-4, gate_time=100, measurement_time=500)\n",
    "baseline = estimate(\n",
    "    app, baseline_arch,\n",
    "    isa_query=SurfaceCode.q() * Litinski19Factory.q(),\n",
    "    max_error=0.01,\n",
    "    name=\"Built-in models\",\n",
    ")\n",
    "baseline.add_qubit_partition_column()\n",
    "baseline.add_factory_summary_column()\n",
    "baseline.as_frame()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef447c3b",
   "metadata": {},
   "source": [
    "## Building a custom architecture model\n",
    "\n",
    "An `Architecture` defines the physical instruction set of a quantum computer:\n",
    "the native operations the hardware can perform, each with a gate time and error\n",
    "rate.\n",
    "\n",
    "The built-in `GateBased` architecture uses a single error rate for all gates.\n",
    "In practice, two-qubit gates are typically noisier and slower than single-qubit\n",
    "gates, and measurement fidelities may differ from gate fidelities.  Let's build\n",
    "a more flexible architecture that models these differences.\n",
    "\n",
    "To implement a custom architecture, subclass `Architecture` and implement one\n",
    "method: `provided_isa`.  This method receives an `ISAContext` and uses it to\n",
    "register each physical instruction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "5e98f44a",
   "metadata": {},
   "outputs": [],
   "source": [
    "@dataclass\n",
    "class ParameterizedArchitecture(Architecture):\n",
    "    \"\"\"\n",
    "    A configurable architecture with separate timing and error parameters for\n",
    "    single-qubit gates, two-qubit gates, and measurements.\n",
    "\n",
    "    Unlike the built-in ``GateBased`` model (which uses one error rate for all\n",
    "    operations), this model lets you specify different error rates for each gate\n",
    "    class, reflecting hardware where two-qubit gates are noisier than\n",
    "    single-qubit gates.\n",
    "    \"\"\"\n",
    "\n",
    "    _: KW_ONLY\n",
    "    single_qubit_gate_time: int\n",
    "    two_qubit_gate_time: int\n",
    "    measurement_time: int\n",
    "    single_qubit_error_rate: float\n",
    "    two_qubit_error_rate: float\n",
    "    measurement_error_rate: float\n",
    "\n",
    "    def provided_isa(self, ctx: ISAContext) -> ISA:\n",
    "        instructions = []\n",
    "\n",
    "        # Single-qubit gates: Clifford gates and T gates\n",
    "        for gate_id in [H, S, S_DAG, T, T_DAG]:\n",
    "            instructions.append(\n",
    "                ctx.add_instruction(\n",
    "                    gate_id,\n",
    "                    encoding=PHYSICAL,\n",
    "                    arity=1,\n",
    "                    time=self.single_qubit_gate_time,\n",
    "                    error_rate=self.single_qubit_error_rate,\n",
    "                )\n",
    "            )\n",
    "\n",
    "        # Measurements\n",
    "        for meas_id in [MEAS_X, MEAS_Y, MEAS_Z]:\n",
    "            instructions.append(\n",
    "                ctx.add_instruction(\n",
    "                    meas_id,\n",
    "                    encoding=PHYSICAL,\n",
    "                    arity=1,\n",
    "                    time=self.measurement_time,\n",
    "                    error_rate=self.measurement_error_rate,\n",
    "                )\n",
    "            )\n",
    "\n",
    "        # Two-qubit entangling gates\n",
    "        for gate_id in [CNOT, CZ]:\n",
    "            instructions.append(\n",
    "                ctx.add_instruction(\n",
    "                    gate_id,\n",
    "                    encoding=PHYSICAL,\n",
    "                    arity=2,\n",
    "                    time=self.two_qubit_gate_time,\n",
    "                    error_rate=self.two_qubit_error_rate,\n",
    "                )\n",
    "            )\n",
    "\n",
    "        return ctx.make_isa(*instructions)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee910f8e",
   "metadata": {},
   "source": [
    "### What if my qubits had different characteristics?\n",
    "\n",
    "Let's explore two hypothetical hardware scenarios:\n",
    "\n",
    "- **Fast but noisy:** short gate times, higher error rates (reminiscent of\n",
    "  some superconducting platforms)\n",
    "- **Slow but clean:** longer gate times, lower error rates (reminiscent of\n",
    "  some trapped-ion platforms)\n",
    "\n",
    "We use the built-in `SurfaceCode` and `Litinski19Factory` transforms so that we\n",
    "isolate the effect of the architecture."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "b7f6079c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>encoding</th>\n",
       "      <th>arity</th>\n",
       "      <th>space</th>\n",
       "      <th>time</th>\n",
       "      <th>error</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>id</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>H</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>50</td>\n",
       "      <td>0.0001</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MEAS_X</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>200</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>S</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>50</td>\n",
       "      <td>0.0001</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>T</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>50</td>\n",
       "      <td>0.0001</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MEAS_Y</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>200</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CZ</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>2</td>\n",
       "      <td>2</td>\n",
       "      <td>100</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>S_DAG</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>50</td>\n",
       "      <td>0.0001</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>T_DAG</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>50</td>\n",
       "      <td>0.0001</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MEAS_Z</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>200</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CNOT</th>\n",
       "      <td>PHYSICAL</td>\n",
       "      <td>2</td>\n",
       "      <td>2</td>\n",
       "      <td>100</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        encoding  arity  space  time   error\n",
       "id                                          \n",
       "H       PHYSICAL      1      1    50  0.0001\n",
       "MEAS_X  PHYSICAL      1      1   200  0.0005\n",
       "S       PHYSICAL      1      1    50  0.0001\n",
       "T       PHYSICAL      1      1    50  0.0001\n",
       "MEAS_Y  PHYSICAL      1      1   200  0.0005\n",
       "CZ      PHYSICAL      2      2   100  0.0005\n",
       "S_DAG   PHYSICAL      1      1    50  0.0001\n",
       "T_DAG   PHYSICAL      1      1    50  0.0001\n",
       "MEAS_Z  PHYSICAL      1      1   200  0.0005\n",
       "CNOT    PHYSICAL      2      2   100  0.0005"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fast_noisy = ParameterizedArchitecture(\n",
    "    single_qubit_gate_time=50,\n",
    "    two_qubit_gate_time=100,\n",
    "    measurement_time=200,\n",
    "    single_qubit_error_rate=1e-4,\n",
    "    two_qubit_error_rate=5e-4,\n",
    "    measurement_error_rate=5e-4,\n",
    ")\n",
    "\n",
    "slow_clean = ParameterizedArchitecture(\n",
    "    single_qubit_gate_time=500,\n",
    "    two_qubit_gate_time=1000,\n",
    "    measurement_time=1000,\n",
    "    single_qubit_error_rate=1e-6,\n",
    "    two_qubit_error_rate=5e-6,\n",
    "    measurement_error_rate=1e-5,\n",
    ")\n",
    "\n",
    "# Inspect the physical ISA provided by the fast-but-noisy architecture\n",
    "fast_noisy.provided_isa(fast_noisy.context()).as_frame()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "de4ec193",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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rsLCQoWFhXm7HAAAAJzF2bzm8hzbwsJCFRQUOLRFRkbq0KFDKioqcr1SAAAAwA1cDra33367Pvroo3Lt//3vf3X77be7pSgAAADAVS4H21WrVqlXr17l2nv27KlVq1a5pSgAAADAVS4H25KSEp08ebJce2lpqY4dO+aWogAAAABXuRxsO3furDfffLNc++uvv66OHTu6pSgAAADAVS4/7mvixIlKTk7Whg0b1KdPH0nSokWLlJWVpYULF7q9QAAAAMAZLp+xTUpK0ooVKxQbG6v//ve/+vzzz9WiRQtt3LhR3bp180SNAAAAwHm55Tm2l6KMjAxlZGTIZrNp+/btPMcWAACgmnL2ObZOBduioiL7Rs73rNpLLRzyggYAAIDqzdm85tQc24iICOXm5qpBgwaqU6dOhW8YMwxDFotFNput6lUDAAAAVeRUsP3+++8VGRkpSVq8eLFHCwIAAACqosbOsT2NqQgAAADVm7N5zeWnIixYsEDLli2zf8/IyFC7du1055136tChQ1WrFgAAALhALgfbxx57zH4D2aZNmzRmzBj17dtXOTk5GjNmjNsLBAAAAJzh8gsacnJyFBcXJ0maM2eO+vXrp+eee07r1q1T37593V4gAAAA4AyXz9j6+/vr6NGjkqTvvvtOf/7znyVJkZGR530UGAAAAOApLp+xveaaazRmzBglJSVp9erVmj17tiRp+/btiomJcXuBAAAAgDNcPmM7depU1apVS5988ommTZumxo0bS5K+/vprpaamur1AAAAAwBk87ovHfQEAAFRrHnvcV48ePTRr1iwdO3bsggoEAAAA3MnlYNu+fXs9+uijio6O1j333KOVK1d6oi6Py8jIUFxcnBITE71dCgAAANygSlMRTp48qfnz52vmzJn6+uuv1aJFCw0fPlyDBw9WVFSUJ+r0GKYiAAAAVG8em4ogSbVq1dLNN9+szz77THv37tWdd96pp556SrGxserfv7++//77KhcOAAAAVEWVgu1pq1ev1vjx4/Xyyy+rQYMGGjdunOrVq6cbbrhBjz76qLtqBAAAAM7L5akI+fn5eu+99zR9+nTt2LFD/fr10913362UlBRZLBZJ0rJly5Samqri4mKPFO1OTEUAAACo3pzNay6/oCEmJkaXX365hg8frrS0NNWvX79cn/j4eG7KAgAAwEXlcrBdtGiRunXr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OsbSpUvVr18/NWrUSBaLRfPmzauwX0ZGhpo1a6bAwEB16dJFq1evdmsdqJpp06YpPj5eYWFhCgsLU9euXfX111+7dQyOEdc8//zzslgsGj16tFu3y+9gDr///rvuuusu1a1bV0FBQWrbtq3WrFnjtu1znFzaCLYwtSVLlmjEiBFauXKlvv32W5WWlurPf/6zrFZrhf2XL1+u0tLScu1btmzR/v37K1zHarUqISFBGRkZldYxe/ZsjRkzRuPHj9e6deuUkJCglJQU5efn2/u0a9dObdq0KffZt2+fi3sNV8TExOj555/X2rVrtWbNGvXu3Vs33nijfvrppwr7c4x4VlZWlt544w3Fx8efsx+/Q8106NAhJSUlyc/PT19//bW2bNmil19+WRERERX25zipgQygBsnPzzckGUuWLCm3zGazGQkJCcYtt9xinDx50t7+888/G1FRUcYLL7xw3u1LMubOnVuuvXPnzsaIESMcxmrUqJGRnp7uUv2LFy82BgwY4NI6cF1ERITx9ttvl2vnGPGsI0eOGFdccYXx7bffGj169DAefvjhCvvxO9RcTzzxhHHNNdc41ZfjpGbijC1qlMLCQklSZGRkuWU+Pj766quvtH79eg0ZMkRlZWX69ddf1bt3b/Xv31+PP/54lcY8ceKE1q5dq+TkZIexkpOTtWLFiqrtCDzCZrPpo48+ktVqVdeuXcst5xjxrBEjRuj66693+DtUhN+h5po/f746deqkgQMHqkGDBmrfvr3eeuutCvtynNRMtbxdAHCxlJWVafTo0UpKSlKbNm0q7NOoUSN9//336tatm+68806tWLFCycnJmjZtWpXHPXjwoGw2m6Kiohzao6Ki9PPPPzu9neTkZG3YsEFWq1UxMTH6+OOPKwxfcN2mTZvUtWtXHT9+XKGhoZo7d67i4uIq7Msx4hkfffSR1q1bp6ysLKf68zvUTL/99pumTZumMWPG6O9//7uysrI0atQo+fv7a+jQoeX6c5zUPARb1BgjRozQ5s2btWzZsnP2a9Kkid577z316NFDl112md555x1ZLJaLVGXlvvvuO2+XYFqtWrVSdna2CgsL9cknn2jo0KFasmRJpeGWY8S99uzZo4cffljffvutAgMDnV6P36HmKSsrU6dOnfTcc89Jktq3b6/Nmzfr9ddfrzDYShwnNQ1TEVAjjBw5Ul988YUWL16smJiYc/bdv3+/7r33XvXr109Hjx7V3/72twsau169evL19S13o8L+/fsVHR19QduGe/j7+6tFixbq2LGj0tPTlZCQoMmTJ1fan2PEvdauXav8/Hx16NBBtWrVUq1atbRkyRJNmTJFtWrVks1mq3A9foeap2HDhuX+D2fr1q21e/fuStfhOKlZCLYwNcMwNHLkSM2dO1fff/+9mjdvfs7+Bw8eVJ8+fdS6dWt9+umnWrRokWbPnq1HH320yjX4+/urY8eOWrRokb2trKxMixYt4rJTNVVWVqaSkpIKl3GMuF+fPn20adMmZWdn2z+dOnXSoEGDlJ2dLV9f33Lr8DvUTElJSeUe2bh9+3Y1bdq0wv4cJzWQt+9eAzzpgQceMMLDw43MzEwjNzfX/jl69Gi5vjabzejUqZPRt29fo6SkxN6enZ1tREZGGq+88kqFYxw5csRYv369sX79ekOS8corrxjr1683du3aZe/z0UcfGQEBAcaMGTOMLVu2GPfee69Rp04dIy8vz/07DZeMHTvWWLJkiZGTk2Ns3LjRGDt2rGGxWIyFCxeW68sxcvGc76kI/A410+rVq41atWoZzz77rLFjxw7jgw8+MIKDg43333+/XF+Ok5qJYAtTk1ThZ/r06RX2X7hwoXHs2LFy7evWrTP27NlT4TqLFy+ucIyhQ4c69HvttdeMJk2aGP7+/kbnzp2NlStXXujuwQ2GDx9uNG3a1PD39zfq169v9OnTp8JQexrHyMVxrmBrGPwONdnnn39utGnTxggICDCuvPJK480336y0L8dJzWMxDMO4GGeGAQAAAE9iji0AAABMgWALAAAAUyDYAgAAwBQItgAAADAFgi0AAABMgWALAAAAUyDYAgAAwBQItgAAADAFgi0AAABMgWALANVYz549NXr0aK+N3717d3344Yce2/6CBQvUrl07lZWVeWwMADUHwRYAziEtLU0Wi0UWi0V+fn5q3ry5Hn/8cR0/ftyt42RmZspisejw4cMO7Z9++qn++c9/unUsZ82fP1/79+/X7bff7rExUlNT5efnpw8++MBjYwCoOQi2AHAeqampys3N1W+//aZXX31Vb7zxhsaPH39Rxo6MjFTt2rUvylhnmzJlioYNGyYfH8/+qyItLU1Tpkzx6BgAagaCLQCcR0BAgKKjoxUbG6v+/fsrOTlZ3377rX15s2bNNGnSJId12rVrpwkTJti/WywWvf3227rpppsUHBysK664QvPnz5ck7dy5U7169ZIkRUREyGKxKC0tTVL5qQjNmjXTxIkTNWTIEIWGhqpp06aaP3++Dhw4oBtvvFGhoaGKj4/XmjVrHOpZtmyZunXrpqCgIMXGxmrUqFGyWq2V7vOBAwf0/fffq1+/fg7tFotFb7zxhm644QYFBwerdevWWrFihX755Rf17NlTISEhuvrqq/Xrr7/a19mwYYN69eql2rVrKywsTB07dnSor1+/flqzZo3DOgBQFQRbAHDB5s2b9eOPP8rf39/ldZ955hndeuut2rhxo/r27atBgwapoKBAsbGxmjNnjiRp27Ztys3N1eTJkyvdzquvvqqkpCStX79e119/vQYPHqwhQ4borrvu0rp163T55ZdryJAhMgxDkvTrr78qNTVVAwYM0MaNGzV79mwtW7ZMI0eOrHSMZcuW2YPr2f75z39qyJAhys7O1pVXXqk777xT9913n8aNG6c1a9bIMAyHbQ8aNEgxMTHKysrS2rVrNXbsWPn5+dmXN2nSRFFRUfrhhx9c/psCwJkItgBwHl988YVCQ0MVGBiotm3bKj8/X4899pjL20lLS9Mdd9yhFi1a6LnnnlNxcbFWr14tX19fRUZGSpIaNGig6OhohYeHV7qdvn376r777tMVV1yhp59+WkVFRUpMTNTAgQPVsmVLPfHEE9q6dav2798vSUpPT9egQYM0evRoXXHFFbr66qs1ZcoUzZo1q9K5wrt27VJUVFSF0xCGDRumW2+91T7Wzp07NWjQIKWkpKh169Z6+OGHlZmZae+/e/duJScn68orr9QVV1yhgQMHKiEhwWGbjRo10q5du1z9kwKAA4ItAJxHr169lJ2drVWrVmno0KEaNmyYBgwY4PJ24uPj7f8cEhKisLAw5efnX9B2oqKiJElt27Yt13Z62xs2bNCMGTMUGhpq/6SkpKisrEw5OTkVjnHs2DEFBgZWefzjx4+rqKhIkjRmzBjdfffdSk5O1vPPP1/hlIOgoCAdPXr0/DsPAOdAsAWA8wgJCVGLFi2UkJCgd999V6tWrdI777xjX+7j42O/7H9aaWlpue2cefldOjVftSqPuTpzOxaLpdK209suLi7Wfffdp+zsbPtnw4YN2rFjhy6//PIKx6hXr54OHTrklvEnTJign376Sddff72+//57xcXFae7cuQ7bLCgoUP369Z3YewCoHMEWAFzg4+Ojv//973ryySd17NgxSVL9+vWVm5tr71NUVFTpmdDKnJ6za7PZ3Ffs/+nQoYO2bNmiFi1alPtUNle4ffv2ysvLqzTcuqply5b629/+poULF+rmm2/W9OnT7cuOHz+uX3/9Ve3bt3fLWABqLoItALho4MCB8vX1VUZGhiSpd+/eeu+99/TDDz9o06ZNGjp0qHx9fV3aZtOmTWWxWPTFF1/owIEDKi4udlu9TzzxhH788UeNHDlS2dnZ2rFjhz777LNz3jzWvn171atXT8uXL7+gsY8dO6aRI0cqMzNTu3bt0vLly5WVleVwU9rKlSsVEBCgrl27XtBYAECwBQAX1apVSyNHjtSLL74oq9WqcePGqUePHrrhhht0/fXXq3///pVe4q9M48aN9cwzz2js2LGKioo6Z+h0VXx8vJYsWaLt27erW7duat++vZ5++mk1atSo0nV8fX01bNiwC35xgq+vr/744w8NGTJELVu21K233qrrrrtOzzzzjL3Pf/7zHw0aNEjBwcEXNBYAWIyzJ4YBACApLy9Pf/rTn7Ru3To1bdrUI2McPHhQrVq10po1a9S8eXOPjAGg5uCMLQCgQtHR0XrnnXe0e/duj42xc+dO/fvf/ybUAnALztgCAADAFDhjCwAAAFMg2AIAAMAUCLYAAAAwBYItAAAATIFgCwAAAFMg2AIAAMAUCLYAAAAwBYItAAAATIFgCwAAAFP4/6B/FjWe/X9dAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isa_query = SurfaceCode.q() * Litinski19Factory.q()\n",
    "\n",
    "results = [\n",
    "    estimate(app, fast_noisy, isa_query, max_error=0.01, name=\"Fast but noisy\"),\n",
    "    estimate(app, slow_clean, isa_query, max_error=0.01, name=\"Slow but clean\"),\n",
    "    baseline,\n",
    "]\n",
    "\n",
    "plot_estimates(results, figsize=(8, 5), runtime_unit=\"ms\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4cd8012",
   "metadata": {},
   "source": [
    "## Building a custom QEC ISA transform\n",
    "\n",
    "An `ISATransform` maps one instruction set to another.  A QEC transform\n",
    "consumes physical instructions and produces logical instructions by encoding\n",
    "qubits in an error-correcting code.\n",
    "\n",
    "The key relationships in any QEC code are:\n",
    "\n",
    "- **Space**: How many physical qubits per logical qubit?  (Depends on code\n",
    "  distance.)\n",
    "- **Time**: How long does one logical operation take?  (Depends on syndrome\n",
    "  extraction cycles.)\n",
    "- **Error**: What is the logical error rate?  (Depends on physical error rate,\n",
    "  code distance, and the code's threshold.)\n",
    "\n",
    "To implement a QEC transform, subclass `ISATransform` and implement two\n",
    "methods:\n",
    "\n",
    "1. `required_isa`: a **static method** that declares what physical\n",
    "   instructions the transform needs.  Because it is static, it cannot reference\n",
    "   instance fields (such as the error-correction threshold); instead, you\n",
    "   specify fixed bounds using `ConstraintBound`.  `ConstraintBound` supports\n",
    "   comparisons like `.lt(value)` (less than), `.le(value)`, `.eq(value)`,\n",
    "   `.gt(value)`, and `.ge(value)`.\n",
    "2. `provided_isa`: computes the logical instruction properties from the\n",
    "   physical ones and yields one or more ISAs.\n",
    "\n",
    "The `distance` field uses `metadata={\"domain\": range(3, 22, 2)}` to tell the\n",
    "estimator to automatically search over odd distances from 3 to 21.  The\n",
    "estimator evaluates all distances and keeps only the Pareto-optimal ones."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "3f829830",
   "metadata": {},
   "outputs": [],
   "source": [
    "@dataclass\n",
    "class GenericQEC(ISATransform):\n",
    "    \"\"\"\n",
    "    A configurable QEC code model with tunable threshold, overhead,\n",
    "    and error suppression.\n",
    "\n",
    "    This transform consumes physical H, CNOT, and MEAS_Z instructions and\n",
    "    produces a logical LATTICE_SURGERY instruction.  The resource formulas\n",
    "    are parameterized so you can model different QEC code families.\n",
    "\n",
    "    The logical error rate follows:\n",
    "\n",
    "        error = crossing_prefactor × (p_physical / threshold) ^ ⌊(d+1)/2⌋\n",
    "\n",
    "    Space per data qubit is:\n",
    "\n",
    "        qubits_per_data_qubit × d²\n",
    "    \"\"\"\n",
    "\n",
    "    crossing_prefactor: float = 0.03\n",
    "    error_correction_threshold: float = 0.01\n",
    "    qubits_per_data_qubit: int = 2\n",
    "    syndrome_extraction_depth: int = 4\n",
    "    _: KW_ONLY\n",
    "    distance: int = field(default=3, metadata={\"domain\": range(3, 22, 2)})\n",
    "\n",
    "    @staticmethod\n",
    "    def required_isa() -> ISARequirements:\n",
    "        # required_isa is static, so we cannot reference instance fields here.\n",
    "        # Instead, we use ConstraintBound to express fixed constraints on the\n",
    "        # implementation ISA.  ConstraintBound supports .lt(), .le(), .eq(),\n",
    "        # .gt(), and .ge() comparisons.\n",
    "        return ISARequirements(\n",
    "            constraint(H, error_rate=ConstraintBound.lt(0.01)),\n",
    "            constraint(CNOT, arity=2, error_rate=ConstraintBound.lt(0.01)),\n",
    "            constraint(MEAS_Z, error_rate=ConstraintBound.lt(0.01)),\n",
    "        )\n",
    "\n",
    "    def provided_isa(\n",
    "        self, impl_isa: ISA, ctx: ISAContext\n",
    "    ) -> Generator[ISA, None, None]:\n",
    "        cnot = impl_isa[CNOT]\n",
    "        h = impl_isa[H]\n",
    "        meas_z = impl_isa[MEAS_Z]\n",
    "\n",
    "        # Physical error rate is the worst case across all required gates\n",
    "        physical_error_rate = max(\n",
    "            cnot.expect_error_rate(),\n",
    "            h.expect_error_rate(),\n",
    "            meas_z.expect_error_rate(),\n",
    "        )\n",
    "\n",
    "        d = self.distance\n",
    "\n",
    "        # Space: physical qubits per data qubit, scaled by distance².\n",
    "        #\n",
    "        # Because LATTICE_SURGERY has variable arity (it can operate on any\n",
    "        # number of logical qubits), space and error_rate must be provided as\n",
    "        # functions of arity rather than as fixed numbers.  The estimator\n",
    "        # provides several helpers for this:\n",
    "        #\n",
    "        #   linear_function(slope)          → f(n) = slope × n\n",
    "        #   constant_function(value)        → f(n) = value\n",
    "        #   block_linear_function(k, s, o)  → f(n) = s × ⌈n/k⌉ + o\n",
    "        #   generic_function(callable)      → f(n) = callable(n)\n",
    "        #\n",
    "        # For QEC codes, resources scale linearly with the number of logical\n",
    "        # qubits, so linear_function is the natural choice.\n",
    "        space = linear_function(self.qubits_per_data_qubit * d**2)\n",
    "\n",
    "        # Time: syndrome extraction cycle × code distance\n",
    "        code_cycle_time = (\n",
    "            h.expect_time()\n",
    "            + self.syndrome_extraction_depth * cnot.expect_time()\n",
    "            + meas_z.expect_time()\n",
    "        )\n",
    "        time = code_cycle_time * d\n",
    "\n",
    "        # Error: exponential suppression below threshold\n",
    "        logical_error = self.crossing_prefactor * (\n",
    "            (physical_error_rate / self.error_correction_threshold)\n",
    "            ** ((d + 1) // 2)\n",
    "        )\n",
    "        error = linear_function(logical_error)\n",
    "\n",
    "        yield ctx.make_isa(\n",
    "            ctx.add_instruction(\n",
    "                LATTICE_SURGERY,\n",
    "                encoding=LOGICAL,\n",
    "                arity=None,\n",
    "                space=space,\n",
    "                time=time,\n",
    "                error_rate=error,\n",
    "                # transform=self records that this instruction was produced by\n",
    "                # this QEC transform instance, and source=[...] records which\n",
    "                # physical instructions it was derived from.  Together, they\n",
    "                # form the provenance chain that you can inspect in the\n",
    "                # estimation results (see notebook 2).\n",
    "                transform=self,\n",
    "                source=[cnot, h, meas_z],\n",
    "                # Extra keyword arguments (like distance) are stored as\n",
    "                # properties on the instruction.  This lets you retrieve the\n",
    "                # code distance used for each Pareto-optimal result when\n",
    "                # analysing the estimation output.  Further, the property can be\n",
    "                # required and read by a parent ISATransform to create new\n",
    "                # logical instructions based on this one.\n",
    "                distance=d,\n",
    "            ),\n",
    "        )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2981ec35",
   "metadata": {},
   "source": [
    "### What if we had a better QEC code?\n",
    "\n",
    "Let's compare two configurations:\n",
    "\n",
    "- **Surface-code-like:** threshold 1%, prefactor 0.03, ~2d² physical qubits\n",
    "  per logical qubit (the `GenericQEC` defaults).\n",
    "- **Optimistic code:** threshold 3%, prefactor 0.01, ~d² qubits\n",
    "  per logical qubit (a hypothetical code with better parameters).\n",
    "\n",
    "We use the built-in `GateBased` architecture and `Litinski19Factory` to isolate\n",
    "the effect of the QEC code.  Because `GenericQEC` is a dataclass, we can pass\n",
    "the non-default parameters directly to `.q()`. The estimator fixes those values\n",
    "while still searching over the `distance` hyperparameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "175568cb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAs4AAAHCCAYAAAD/xk/KAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAATTdJREFUeJzt3Xt8z/X///H7e+O988aYzeyEIZJNTiEJK1Q++KgUn4wKFeUQRZ9C3/iITlI+dHAopVRCnw6iOYscR+WsOe9AY7ODme31+8PPO2/beL3Zem92u14u78ul9/P5ej2fj/fbxbp77fl8vSyGYRgCAAAAcEUuzi4AAAAAKAsIzgAAAIAJBGcAAADABIIzAAAAYALBGQAAADCB4AwAAACYQHAGAAAATKjg7AJuZPn5+Tp+/Lh8fHxksVicXQ4AAAAuYxiGzpw5o+DgYLm4XPmaMsG5BB0/flyhoaHOLgMAAABXceTIEYWEhFzxGIJzCfLx8ZF04Q/C19fXydUAAADgcunp6QoNDbXltishOJegi8szfH19Cc4AAAClmJlltWwOBAAAAEwgOAMAAAAmEJwBAAAAE1jjDABAGZeXl6fc3FxnlwGUShUrVpSrq2uxjEVwBgCgjDIMQ0lJSTp9+rSzSwFKtUqVKikoKOi6n6tBcAYAoIy6GJqrVasmT09PHrYFXMYwDGVlZSklJUWSVL169esaj+AMAEAZlJeXZwvNVapUcXY5QKnl4eEhSUpJSVG1atWua9kGmwMBACiDLq5p9vT0dHIlQOl38e/J9e4FIDgDAFCGsTwDuLri+ntCcAYAAABMIDjDYelnc5WYll1oX2JattLPckskAABw4yE4wyHpZ3MVO2ujer63QcdP24fn46ez1fO9DYqdtZHwDABwmvfff1+hoaFycXHRlClTnF1Osbrzzjs1dOjQ6xpj3Lhxio6Otr3v27evunXrVqxz3KgIznBIZs55/ZlxTodTs/TQ+3+F5+Ons/XQ+xt0ODVLf2acU2bOeSdXCgC4Gmf9BvHEiRN68sknFRYWJjc3NwUFBaljx45at27ddY+dnp6uwYMH6/nnn9exY8c0YMCAYqj4xvb2229rzpw5JT7PRx99pGbNmsnT01M+Pj5q27atvv32W7tjVq5cKYvFUugrKSnJdlx6err+/e9/66abbpK7u7uCgoIUExOjr7/+WoZhlNhnIDjDIdX9PDSzX0OFVM2xhecth1JtoTmkao5m9muo6n4ezi4VAHAFzvwNYo8ePbRt2zZ99NFH2rt3r7755hvdeeed+vPPP695TMMwdP78eR0+fFi5ubm69957Vb16de46YoKfn58qVapUonOMGDFCAwcOVM+ePbVjxw5t3LhRt99+u7p27ap33323wPF79uxRYmKi3atatWqSpNOnT6tVq1b6+OOPNXr0aG3dulWrV69Wz5499dxzzyktLa3EPgfBGQ45c+6Mxm0aKs/w923hucf09bbQ7Bn+vsZtGqoz5844u1QAwBU46zeIp0+f1po1azRp0iS1a9dO4eHhat68uUaPHq1//OMfkqSDBw/KYrEoPj7e7jyLxaKVK1dK+uvK5A8//KAmTZrIzc1Nn3zyiW655RZJUq1atWSxWHTw4EEdOHBAXbt2VWBgoLy9vdWsWTP99NNPdnXl5OTo+eefV2hoqNzc3BQZGamZM2fa+n/77Td17txZ3t7eCgwM1COPPKKTJ09e8bNebcxVq1apefPmcnNzU/Xq1TVq1CidP//X952Zmak+ffrI29tb1atX1xtvvFHoHCNGjFCNGjXk5eWlFi1a2L4jsy5fqnG57777Tn5+fvr0008lSUeOHNGDDz6oSpUqyd/fX127dtXBgweLPH/Dhg1644039Nprr2nEiBGKjIxU/fr1NWHCBA0dOlTDhw/XkSNH7M6pVq2agoKC7F4uLhdi6wsvvKCDBw/ql19+UWxsrBo0aKC6deuqf//+io+Pl7e3t0Of3xEEZzgkMzdTqdmpSsw6Jmvoe7JUOC1JslQ4LWvoe0rMOqbU7FRl5mY6t1AAwBVV9/PQ5wNuU5i/Z6G/QQzz99TnA24r9t8gent7y9vbW4sWLVJOTs51jzdq1Ci9+uqr2rVrl+666y5bIN64caMSExMVGhqqjIwM3XPPPYqLi9O2bdvUqVMndenSRYcPH7aN06dPH3322WeaOnWqdu3apffee88WwE6fPq327durcePG2rx5s5YsWaLk5GQ9+OCDV6ztSmMeO3ZM99xzj5o1a6bt27dr+vTpmjlzpsaPH287f+TIkVq1apUWL16spUuXauXKldq6davdHIMHD9b69ev1+eefa8eOHXrggQfUqVMn7du377q/W0maN2+eHn74YX366afq3bu3cnNz1bFjR/n4+GjNmjVat26dvL291alTJ507d67QMT777DN5e3tr4MCBBfqeffZZ5ebmasGCBabqyc/P1+eff67evXsrODi4QL+3t7cqVCjB5/sZKDFpaWmGJCMtLc3ZpRSrxIxE464vOhoN5zQ0Grx/h1Fz3DSjwft3GA3nNDTu+qKjkZiR6OwSAeCGl52dbezcudPIzs6+rnGOncoy2kxaboQ//63t1WbScuPYqaxiqrSgr776yqhcubLh7u5utGrVyhg9erSxfft2W39CQoIhydi2bZut7dSpU4YkY8WKFYZhGMaKFSsMScaiRYvsxt62bZshyUhISLhiDTfffLPxzjvvGIZhGHv27DEkGcuWLSv02FdeecW4++677dqOHDliSDL27NlT6DlXG/OFF14w6tWrZ+Tn59vapk2bZnh7ext5eXnGmTNnDKvVanzxxRe2/j///NPw8PAwhgwZYhiGYRw6dMhwdXU1jh07Zjd2hw4djNGjRxf52ceOHWtERUXZ3sfGxhpdu3a1vW/btq0xZMgQ49133zX8/PyMlStX2vrmzp1boO6cnBzDw8PD+PHHHwudr1OnTnbzXc7X19d48sknDcP468/Vy8vL7tWgQQPDMAwjOTnZkGS8+eabRY5XmCv9fXEkr/HIbTgsP9dPWYcGKN/vbblYU+UVMf1C+zl/ZZ0YoPxcPydXCAAwK7iSh97qGaUe09fb2t7qGaXgSiW3V6VHjx669957tWbNGm3YsEE//PCDJk+erA8//FB9+/Z1aKymTZte9ZiMjAyNGzdO3333nRITE3X+/HllZ2fbrjjHx8fL1dVVbdu2LfT87du3a8WKFYUuAThw4IA2bdpkdzX1hx9+UGJi4hXH3LVrl1q2bGn3YI7WrVsrIyNDR48e1alTp3Tu3Dm1aNHC1u/v76969erZ3v/666/Ky8tT3bp17cbOycmxPYb90pr/9a9/acaMGUV+T5f66quvlJKSonXr1qlZs2Z238X+/fvl4+Njd/zZs2d14MCBIsczrrJhz2q12r1fs2aN3RwVK1Y0NU5JIzjDIYlpF9a+HU11U7BrH53xn2Lr88voo6Mn3fTQ+xs0f2Dx/3oPAFD8jp/O1rD52+3ahs3frs8H3Fai4dnd3V133XWX7rrrLr300kt6/PHHNXbsWPXt29e2lvXSkFTUo5K9vLyuOteIESO0bNkyvf7664qMjJSHh4fuv/9+29ICD48rf86MjAx16dJFkyZNKtBXvXp15efn2wXcGjVqFFhDXRIyMjLk6uqqLVu2yNXV1a7vYmC+dJ24r6+v6bEbN26srVu3atasWWratKkt4GdkZKhJkya29c6XCggIKHSsOnXqaO3atTp37lyBgHz8+HGlp6cXCP81a9YsdMNiQECAKlWqpN27d5v+LMWJNc5wiJdbBVXxtiqkao68Q7606/MO+VIhVXNUxdsqLzf+TQYApd2lGwHD/D214MmWdmueL7/bRklq0KCBMjMv7I+5GMASExNt/ZcGQEetW7dOffv2Vffu3XXLLbcoKCjIbjPbLbfcovz8fK1atarQ82+99Vb9/vvvioiIUGRkpN3Ly8tLPj4+dm0eHh5XHbN+/fpav3693T8O1q1bJx8fH4WEhKh27dqqWLGifvnlF1v/qVOntHfvXtv7xo0bKy8vTykpKQXqCgoKkiS7tot3pTCjdu3aWrFihRYvXqynn37a7rvYt2+fqlWrVmBOP7/Cf+P88MMPKyMjQ++9916Bvtdff13u7u7q2bOnqbpcXFz00EMP6dNPP9Xx48cL9GdkZNhtsCxuBGc4xNe9oiY/FCbP8PeVmHVMId4hmtt5rkK8Q5SYdUye4e9r8kNh8nWv6OxSAQBXcPE3iJduBGwS7l9gw2BR93m+Vn/++afat2+vTz75RDt27FBCQoK+/PJLTZ48WV27dpV04QrwbbfdZtv0t2rVKr344ovXPGedOnX09ddfKz4+Xtu3b1evXr2Un59v64+IiFBsbKweffRRLVq0SAkJCVq5cqW++OILSdKgQYOUmpqqhx9+WJs2bdKBAwf0448/ql+/fsrLyyt0zquN+dRTT+nIkSN6+umntXv3bi1evFhjx47V8OHD5eLiIm9vbz322GMaOXKkli9frt9++83uarwk1a1bV71791afPn309ddfKyEhQRs3btTEiRP13XffXfP3den4K1as0IIFC2wPROndu7eqVq2qrl27as2aNbbP9cwzz+jo0aOFjtOyZUsNGTJEI0eO1BtvvKEDBw5o9+7devHFFzV16lR98MEHtqUlF6WkpCgpKcnudfG3DhMmTFBoaKhatGihjz/+WDt37tS+ffs0a9YsNW7cWBkZGdf92Yvk0MpqOORG3ByYmJFodPqqk9FwTkOj01edbBsBi2oHAJSM690cmJZ9zug2bW2hGwEvbhjsNm2tkZZ9rjjKtTl79qwxatQo49ZbbzX8/PwMT09Po169esaLL75oZGX9VcfOnTuNli1bGh4eHkZ0dLSxdOnSQjcHnjp1ym78wjYHJiQkGO3atTM8PDyM0NBQ491337VtgLsoOzvbGDZsmFG9enXDarUakZGRxqxZs2z9e/fuNbp3725UqlTJ8PDwMG666SZj6NChdpvkLne1MVeuXGk0a9bMsFqtRlBQkPH8888bubm5tv4zZ84Y//rXvwxPT08jMDDQmDx5coG6z507Z4wZM8aIiIgwKlasaFSvXt3o3r27sWPHjiLrMrs58KKdO3ca1apVM4YPH24YhmEkJiYaffr0MapWrWq4ubkZtWrVMvr373/VvDNz5kyjSZMmhru7uyHJsFqtxqpVq+yOufjnWthr/fr1tuNOnz5tjBo1yqhTp45htVqNwMBAIyYmxli4cGGhfybFtTnQYhhOXmV9A0tPT5efn5/S0tIcWldUmp05d0ZP/PSEUrNTNbvTbAV5Bdn6kjKT1G9JP/l7+GtGzAz5WH2uMBIA4HqcPXtWCQkJqlmzptzd3a9pjPSzucrMOV/onpTEtGx5uVXgN4goEQcPHlTbtm3VsmVLffrppwXWaBe3K/19cSSvsRAVDvGx+mhGzAxl5mbahWZJCvIK0uxOs+VV0YvQDABlgK97xSKDMRu8UZIiIiK0cuVKffTRR4qPj1eTJk2cXZIpBGc4zMfqU2QwvjxMAwAAFKZmzZoaN26cs8twCJsDAQAAABMIzgAAAIAJBGcAAADABIIzAAAAYALBGQAAADCB4AwAAACYQHAGAAA3nHHjxik6Ovq6xjh48KAsFovi4+OveYy+ffuqW7du11UHSg+CMwAA+NsdOXJEjz76qIKDg2W1WhUeHq4hQ4bozz//dHgsi8WiRYsW2bWNGDFCcXFx11VjaGioEhMT1bBhw6seW1TIfvvttzVnzpzrqsPsd3XnnXfKYrEUeD3xxBN2x61YsUL33HOPqlSpIk9PTzVo0EDPPvusjh07dl11lgcEZwAAyquzaVJaEWEp7diF/hLwxx9/qGnTptq3b58+++wz7d+/XzNmzFBcXJxatmyp1NTU657D29tbVapUua4xXF1dFRQUpAoVrv15cX5+fqpUqdI1n+/od9W/f38lJibavSZPnmzrf++99xQTE6OgoCAtWLBAO3fu1IwZM5SWlqY33njjmussNwyUmLS0NEOSkZaW5uxSAAA3mOzsbGPnzp1Gdnb2NQ5w2jA+6GAYUxoZxukj9n2nj1xo/6DDheOKWadOnYyQkBAjKyvLrj0xMdHw9PQ0nnjiCVtbeHi48X//93/GQw89ZHh6ehrBwcHGu+++a9cvyfYKDw83DMMwxo4da0RFRdmOi42NNbp27WpMmDDBqFatmuHn52e8/PLLRm5urjFixAijcuXKRo0aNYxZs2bZzklISDAkGdu2bTMMwzBSU1ONXr16GVWrVjXc3d2NyMhI2/GX1iDJaNu2rd28F+Xl5RmTJk0yateubVitViM0NNQYP358sXxXbdu2NYYMGVLkWEeOHDGsVqsxdOjQQvtPnTpV5Lll3ZX+vjiS17jiDABAeZSTIWWekE4dlObcK6UdvdCedvTC+1MHL/TnZBTrtKmpqfrxxx/11FNPycPDw64vKChIvXv31vz582UYhq39tddeU1RUlLZt26ZRo0ZpyJAhWrZsmSRp06ZNkqTZs2crMTHR9r4wy5cv1/Hjx7V69Wq9+eabGjt2rO677z5VrlxZv/zyi5544gkNHDhQR48eLfT8l156STt37tQPP/ygXbt2afr06apataokaePGjZKkn376SYmJifr6668LHWP06NF69dVXbWPNmzdPgYGBxfZdXcmXX36pc+fO6bnnniu0/3qujJcXBGcAAMojvxpS3++kyhF/hefDv/wVmitHXOj3q1Gs0+7bt0+GYah+/fqF9tevX1+nTp3SiRMnbG2tW7fWqFGjVLduXT399NO6//779dZbb0mSAgICJF0IfUFBQbb3hfH399fUqVNVr149Pfroo6pXr56ysrL0wgsvqE6dOho9erSsVqvWrl1b6PmHDx9W48aN1bRpU0VERCgmJkZdunSxq6NKlSoKCgqSv79/gfPPnDmjt99+W5MnT1ZsbKxq166t22+/XY8//nixfVf//e9/5e3tbff69NNPbeP5+vqqevXqRX5HuLJrX7QDAADKNr+QC+H4YliedfeFdltoDimxqc1eJZWkli1bFng/ZcoUh+e8+eab5eLy1zXDwMBAu41/rq6uqlKlilJSUgo9/8knn1SPHj20detW3X333erWrZtatWplev5du3YpJydHHTp0cKjuq31XVqvV9t+9e/fWv//9b7v+i1e0DcOQxWJxaG7Y44ozAADlmV+I1P19+7bu75dYaI6MjJTFYtGuXbsK7d+1a5cqV658xSvH16pixYp27y0WS6Ft+fn5hZ7fuXNnHTp0SMOGDdPx48fVoUMHjRgxwvT8ly+3uBoz31VAQIDdEgs/Pz9FRkbavXx8fCRJdevWVVpamhITEx2qA38hOAMAUJ6lHZUWDrBvWzjgrzXPxaxKlSq666679N///lfZ2dl2fUlJSfr000/Vs2dPuyujGzZssDtuw4YNdssXKlasqLy8vBKp93IBAQGKjY3VJ598oilTpuj99y/8o+PiVd8r1VGnTh15eHiYvk2eme+qb9++pmu///77ZbVa7e6ycanTp0+bHqu8IjgDAFBeXboRsHKE9OhS+zXPJRSe3333XeXk5Khjx45avXq1jhw5oiVLluiuu+5SjRo1NGHCBLvj161bp8mTJ2vv3r2aNm2avvzySw0ZMsTWHxERobi4OCUlJenUqVMlUrMkjRkzRosXL9b+/fv1+++/69tvv7UF+GrVqsnDw0NLlixRcnKy0tIK3srP3d1dzz//vJ577jl9/PHHOnDggDZs2KCZM2cWOeeVvqu6detqzJgxdsdnZWUpKSnJ7nXxOwkNDdVbb72lt99+W4899phWrVqlQ4cOad26dRo4cKBeeeWVYvy2bkwEZwAAyqO0YwU3Aoa1KLhhsKj7PF+HOnXqaPPmzapVq5YefPBB1a5dWwMGDFC7du20fv36Ahvrnn32WW3evFmNGzfW+PHj9eabb6pjx462/jfeeEPLli1TaGioGjduXOz1XmS1WjV69Gg1atRId9xxh1xdXfX5559LkipUqKCpU6fqvffeU3BwsLp27VroGC+99JKeffZZjRkzRvXr11fPnj2LXFMtXfiuNm3aZPuuwsPD1blzZ9WtW1fr1q2Tt7e33fEffPCBqlevbvd6+OGHbf1PPfWUli5dqmPHjql79+666aab9Pjjj8vX19ehZSfllcVwZHU+HJKeni4/Pz+lpaXJ19fX2eUAAG4gZ8+eVUJCgmrWrCl3d/drGCBN+qTHhVvOXb4R8OKVaK8A6V8LJHe/4ivcQRERERo6dKiGDh3qtBpKm7Fjx+rNN9/UsmXLdNtttzm7nDLhSn9fHMlr3FUDAIDyyN3vQijOySh4yzm/EKnv95Kbt1NDMwr38ssvKyIiQhs2bFDz5s3t7hSCkkVwBgCgvHL3KzoYF/P9m1G8+vXr5+wSyiWCMwAAKLUOHjzo7BIAG67tAwAAACYQnAEAAAATCM4AAACACQRnAAAAwASCMwAAAGACwRkAAAAwgeAMAADKpDlz5qhSpUq29+PGjVN0dLTD46xcuVIWi0WnT58uttpK0rXUGxERoSlTppRYTeUFwRkAAPyt+vbtK4vFYntVqVJFnTp10o4dOxwap2fPntq7d+8V5+nWrdtVx2nVqpUSExPl58dTEnFlBGcAAMqpM+fOKCkzqdC+pMwknTl3psTm7tSpkxITE5WYmKi4uDhVqFBB9913n0NjeHh4qFq1atddi9VqVVBQkCwWy3WPhRsbwRkAgHLozLkzeuKnJ9RvSb8C4TkpM0n9lvTTEz89UWLh2c3NTUFBQQoKClJ0dLRGjRqlI0eO6MSJE5IKX44QHx8vi8Vie5rg5Us1LjVu3Dh99NFHWrx4se3K9sqVKws99vK5Lo77448/qn79+vL29rYF/aJcHOPHH39U48aN5eHhofbt2yslJUU//PCD6tevL19fX/Xq1UtZWVm283JycvTMM8+oWrVqcnd31+23365NmzbZjf3999+rbt268vDwULt27Qp9muLatWvVpk0beXh4KDQ0VM8884wyMzMLrdUwDI0bN05hYWFyc3NTcHCwnnnmmSI/G/5CcAYAoBzKzM1UanaqjmYctQvPF0Pz0YyjSs1OVWZu4eGrOGVkZOiTTz5RZGSkqlSpUixjjhgxQg8++KDdle1WrVqZPj8rK0uvv/665s6dq9WrV+vw4cMaMWLEVc8bN26c3n33Xf388886cuSIHnzwQU2ZMkXz5s3Td999p6VLl+qdd96xHf/cc89pwYIF+uijj7R161ZFRkaqY8eOSk1NlSQdOXJE//znP9WlSxfFx8fr8ccf16hRo+zmPHDggDp16qQePXpox44dmj9/vtauXavBgwcXWuOCBQv01ltv6b333tO+ffu0aNEi3XLLLaa/m/KM4AwAQDkU5BWk2Z1mK8Q7xBae41PibaE5xDtEszvNVpBXUInM/+2338rb21ve3t7y8fHRN998o/nz58vFpXiiibe3tzw8POyubFutVtPn5+bmasaMGWratKluvfVWDR48WHFxcVc9b/z48WrdurUaN26sxx57TKtWrdL06dPVuHFjtWnT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5Ur9+OOPBY7l50YJcvZtPQCgvJFU6Gv27NmFHr906VIjOzu7QPvWrVuNI0eOFHrOihUrCp0jNjbW7rh33nnHCAsLM6xWq9G8eXNjw4YN1/vxAJSARx991AgPDzesVqsREBBgdOjQwVi6dGmRx/Nzo2RYDMMw/v64DgAAAJQtrHEGAAAATCA4AwAAACYQnAEAAAATCM4AAACACQRnAAAAwASCMwAAAGACwRkAAAAwgeAMAAAAmEBwBgAAAEwgOANAOXXnnXdq6NChTpv/jjvu0Lx580ps/CVLlig6Olr5+fklNgeA8oXgDABO0rdvX1ksFlksFlWsWFE1a9bUc889p7NnzxbrPCtXrpTFYtHp06ft2r/++mu98sorxTqXWd98842Sk5P10EMPldgcnTp1UsWKFfXpp5+W2BwAyheCMwA4UadOnZSYmKg//vhDb731lt577z2NHTv2b5nb399fPj4+f8tcl5s6dar69esnF5eS/d9Q3759NXXq1BKdA0D5QXAGACdyc3NTUFCQQkND1a1bN8XExGjZsmW2/oiICE2ZMsXunOjoaI0bN8723mKx6MMPP1T37t3l6empOnXq6JtvvpEkHTx4UO3atZMkVa5cWRaLRX379pVUcKlGRESExo8frz59+sjb21vh4eH65ptvdOLECXXt2lXe3t5q1KiRNm/ebFfP2rVr1aZNG3l4eCg0NFTPPPOMMjMzi/zMJ06c0PLly9WlSxe7dovFovfee0/33XefPD09Vb9+fa1fv1779+/XnXfeKS8vL7Vq1UoHDhywnbN9+3a1a9dOPj4+8vX1VZMmTezq69KlizZv3mx3DgBcK4IzAJQSv/32m37++WdZrVaHz3355Zf14IMPaseOHbrnnnvUu3dvpaamKjQ0VAsWLJAk7dmzR4mJiXr77beLHOett95S69attW3bNt1777165JFH1KdPH/3rX//S1q1bVbt2bfXp00eGYUiSDhw4oE6dOqlHjx7asWOH5s+fr7Vr12rw4MFFzrF27VpbML7cK6+8oj59+ig+Pl433XSTevXqpYEDB2r06NHavHmzDMOwG7t3794KCQnRpk2btGXLFo0aNUoVK1a09YeFhSkwMFBr1qxx+DsFgMsRnAHAib799lt5e3vL3d1dt9xyi1JSUjRy5EiHx+nbt68efvhhRUZG6j//+Y8yMjK0ceNGubq6yt/fX5JUrVo1BQUFyc/Pr8hx7rnnHg0cOFB16tTRmDFjlJ6ermbNmumBBx5Q3bp19fzzz2vXrl1KTk6WJE2cOFG9e/fW0KFDVadOHbVq1UpTp07Vxx9/XORa7UOHDikwMLDQZRr9+vXTgw8+aJvr4MGD6t27tzp27Kj69etryJAhWrlype34w4cPKyYmRjfddJPq1KmjBx54QFFRUXZjBgcH69ChQ45+pQBQAMEZAJyoXbt2io+P1y+//KLY2Fj169dPPXr0cHicRo0a2f7by8tLvr6+SklJua5xAgMDJUm33HJLgbaLY2/fvl1z5syRt7e37dWxY0fl5+crISGh0Dmys7Pl7u5+zfOfPXtW6enpkqThw4fr8ccfV0xMjF599dVCl2R4eHgoKyvr6h8eAK6C4AwATuTl5aXIyEhFRUVp1qxZ+uWXXzRz5kxbv4uLi21ZxEW5ubkFxrl0eYJ0Yb3wtdyG7dJxLBZLkW0Xx87IyNDAgQMVHx9ve23fvl379u1T7dq1C52jatWqOnXqVLHMP27cOP3++++69957tXz5cjVo0EALFy60GzM1NVUBAQEmPj0AXBnBGQBKCRcXF73wwgt68cUXlZ2dLUkKCAhQYmKi7Zj09PQir+QW5eKa6by8vOIr9v+79dZbtXPnTkVGRhZ4FbVWu3HjxkpKSioyPDuqbt26GjZsmJYuXap//vOfmj17tq3v7NmzOnDggBo3blwscwEo3wjOAFCKPPDAA3J1ddW0adMkSe3bt9fcuXO1Zs0a/frrr4qNjZWrq6tDY4aHh8tisejbb7/ViRMnlJGRUWz1Pv/88/r55581ePBgxcfHa9++fVq8ePEVNwc2btxYVatW1bp1665r7uzsbA0ePFgrV67UoUOHtG7dOm3atMlu0+GGDRvk5uamli1bXtdcACARnAGgVKlQoYIGDx6syZMnKzMzU6NHj1bbtm1133336d5771W3bt2KXAJRlBo1aujll1/WqFGjFBgYeMVQ66hGjRpp1apV2rt3r9q0aaPGjRtrzJgxCg4OLvIcV1dX9evX77ofTOLq6qo///xTffr0Ud26dfXggw+qc+fOevnll23HfPbZZ+rdu7c8PT2vay4AkCSLcfniOQAASlhSUpJuvvlmbd26VeHh4SUyx8mTJ1WvXj1t3rxZNWvWLJE5AJQvXHEGAPztgoKCNHPmTB0+fLjE5jh48KD++9//EpoBFBuuOAMAAAAmcMUZAAAAMIHgDAAAAJhAcAYAAABMIDgDAAAAJhCcAQAAABMIzgAAAIAJBGcAAADABIIzAAAAYALBGQAAADDh/wEL++SoBnGhLgAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arch = GateBased(error_rate=1e-4, gate_time=100, measurement_time=500)\n",
    "\n",
    "# Surface-code-like parameters (the defaults)\n",
    "surface_like = GenericQEC.q() * Litinski19Factory.q()\n",
    "\n",
    "# Optimistic hypothetical code: higher threshold, lower overhead\n",
    "optimistic = GenericQEC.q(\n",
    "    crossing_prefactor=0.01,\n",
    "    error_correction_threshold=0.03,\n",
    "    qubits_per_data_qubit=1,\n",
    ") * Litinski19Factory.q()\n",
    "\n",
    "results = [\n",
    "    estimate(app, arch, surface_like, max_error=0.01, name=\"Surface-code-like QEC\"),\n",
    "    estimate(app, arch, optimistic, max_error=0.01, name=\"Optimistic QEC\"),\n",
    "    baseline,\n",
    "]\n",
    "\n",
    "plot_estimates(results, figsize=(8, 5), runtime_unit=\"ms\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6229d30a",
   "metadata": {},
   "source": [
    "## Building a custom factory transform\n",
    "\n",
    "A factory transform produces high-fidelity magic states (typically T states) by\n",
    "consuming lower-level instructions.  It models the distillation process: take\n",
    "many noisy copies of a state, run a distillation protocol, and output fewer\n",
    "copies with lower error.\n",
    "\n",
    "The built-in `Litinski19Factory` uses pre-computed protocol data from\n",
    "[arXiv:1905.06903](https://arxiv.org/abs/1905.06903).  Each entry in the table\n",
    "specifies an output error rate, a space cost in physical qubits (which already\n",
    "accounts for the QEC overhead inside the factory), and a time cost in syndrome\n",
    "extraction cycles.\n",
    "\n",
    "We can build a custom factory that starts from this data and explores \"what if\"\n",
    "scenarios by scaling the space and cycle costs:\n",
    "\n",
    "- `space_factor < 1`: What if the factory were more compact?\n",
    "- `cycle_factor < 1`: What if distillation were faster?\n",
    "\n",
    "This lets you study how improvements in factory design propagate through the\n",
    "full resource estimate, without having to derive the protocols from scratch."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "3f4951e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Reference data from Litinski (arXiv:1905.06903), Table 1.\n",
    "# Assumes Clifford and T error rates at most 1e-4.\n",
    "# Each tuple: (output_error_rate, space_in_physical_qubits, cycles)\n",
    "_LITINSKI_TABLE = [\n",
    "    (4.4e-8,    810, 18.1),\n",
    "    (1.5e-9,    762, 36.2),\n",
    "    (9.3e-10,  1150, 18.1),\n",
    "    (1.9e-11,  2070, 30.0),\n",
    "    (2.4e-15, 16400, 90.3),\n",
    "    (6.3e-25, 18600, 67.8),\n",
    "]\n",
    "\n",
    "\n",
    "@dataclass\n",
    "class ScaledLitinskiFactory(ISATransform):\n",
    "    \"\"\"\n",
    "    A factory transform based on the Litinski (2019) distillation protocols,\n",
    "    with configurable scaling factors for space and cycle costs.\n",
    "\n",
    "    The base data is taken directly from Table 1 in arXiv:1905.06903.\n",
    "    Each entry specifies a distillation protocol's output error rate, space\n",
    "    footprint (in physical qubits), and time (in syndrome extraction cycles).\n",
    "    The space already includes the QEC overhead within the factory itself.\n",
    "\n",
    "    Scaling factors let you explore hypothetical improvements:\n",
    "\n",
    "    - ``space_factor=0.5`` models a factory that uses half the qubits.\n",
    "    - ``cycle_factor=0.5`` models a factory that runs twice as fast.\n",
    "\n",
    "    Note:\n",
    "        The error rates are kept fixed when scaling.  In practice, changing\n",
    "        space or cycles would affect error rates too, but modelling that\n",
    "        relationship requires protocol-specific analysis.\n",
    "    \"\"\"\n",
    "\n",
    "    space_factor: float = 1.0\n",
    "    cycle_factor: float = 1.0\n",
    "\n",
    "    @staticmethod\n",
    "    def required_isa() -> ISARequirements:\n",
    "        return ISARequirements(\n",
    "            constraint(T, error_rate=ConstraintBound.le(1e-4)),\n",
    "            constraint(H, error_rate=ConstraintBound.le(1e-4)),\n",
    "            constraint(CNOT, arity=2, error_rate=ConstraintBound.le(1e-4)),\n",
    "            constraint(MEAS_Z, error_rate=ConstraintBound.le(1e-4)),\n",
    "        )\n",
    "\n",
    "    def provided_isa(\n",
    "        self, impl_isa: ISA, ctx: ISAContext\n",
    "    ) -> Generator[ISA, None, None]:\n",
    "        cnot = impl_isa[CNOT]\n",
    "        h = impl_isa[H]\n",
    "        meas_z = impl_isa[MEAS_Z]\n",
    "        t = impl_isa[T]\n",
    "\n",
    "        # Syndrome extraction time from the physical ISA\n",
    "        syndrome_extraction_time = (\n",
    "            4 * cnot.expect_time() + h.expect_time() + meas_z.expect_time()\n",
    "        )\n",
    "\n",
    "        for error_rate, base_space, base_cycles in _LITINSKI_TABLE:\n",
    "            # Apply scaling factors to space and time\n",
    "            space = ceil(base_space * self.space_factor)\n",
    "            time = ceil(syndrome_extraction_time * base_cycles * self.cycle_factor)\n",
    "\n",
    "            yield ctx.make_isa(\n",
    "                ctx.add_instruction(\n",
    "                    T,\n",
    "                    encoding=LOGICAL,\n",
    "                    arity=1,\n",
    "                    space=space,\n",
    "                    time=time,\n",
    "                    error_rate=error_rate,\n",
    "                    transform=self,\n",
    "                    source=[cnot, h, meas_z, t],\n",
    "                ),\n",
    "            )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "739582e7",
   "metadata": {},
   "source": [
    "### What if the factory were more compact or faster?\n",
    "\n",
    "Let's compare three scenarios, all using the built-in `SurfaceCode` for QEC:\n",
    "\n",
    "- **Litinski baseline:** the built-in `Litinski19Factory` (our reference).\n",
    "- **Compact factory:** `space_factor=0.5`: the factory uses half the physical\n",
    "  qubits (perhaps due to better routing or a denser layout).\n",
    "- **Fast factory:** `cycle_factor=0.5`: the factory completes in half the\n",
    "  cycles (perhaps due to a faster syndrome extraction scheme)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1de231fb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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RPRsGBgYPPWV5hIMzkREVOfJ5fIq+xcnET2/eHMgEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkwVMHZ6VSCYVCgTt37lRFPURERERENZLWwXnixIlYt24dgIehuXPnzmjZsiXc3d0RGxtb1fUREREREdUIWgfnn3/+Gf7+/gCA3377DSkpKTh//jwmTZqEDz/8sMoLJCIiIiKqCbQOzllZWXBycgIA7Nq1C/3790fjxo3xzjvv4MyZM1VeYE1QWFgIT09PTJkyRdelEBEREZGOaB2cHR0dkZiYCKVSiejoaLz88ssAHoZLuVxe5QXWBPPmzcMLL7yg6zKIiIiISIe0Ds7Dhw/HgAED0Lx5c8hkMgQFBQEAjh49iiZNmlR5gbp28eJFnD9/HiEhIbouhYiIiIh0SOvgPGfOHHz33XcYNWoUDh8+DCMjIwCAXC7HjBkzqrzAp3Hw4EGEhobCxcUFMpkMO3bsKNVn5cqV8PLygrGxMdq1a4djx45pbJ8yZQoWLFjwjComIiIioppK6+C8YcMGhIaGYtKkSXBzc1O3v/XWW8jJyanS4p5WQUEB/P39sXLlyjK3R0VFYfLkyZg9ezZOnjwJf39/BAcHIzMzEwDwyy+/oHHjxmjcuLGk+e7du4fc3FyNFxERERHVDTIhhNBmB7lcjrS0NDg4OGi0//vvv3BwcIBSqazSAquKTCbD9u3b0bdvX3Vbu3bt0KZNG6xYsQIAoFKp4O7ujnHjxmHGjBmY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+N3oukmb3z4nIiIiomdPm7xWY9Y4ExERERHVZAzOREREREQSMDgTEREREUnA4ExEREREJAGDMxERERGRBAzOtVze/TykF6SXuS29IB159/OecUVEREREdRODcy2Wdz8P7+59F8Ojh5cKz+kF6RgePRzv7n2X4ZmIiIioCjA412IFxQW4XXQb1/Ova4TnktB8Pf86bhfdRkFxgY4rJSIiIqr9GJxrMSczJ0T0jICbuZs6PCsyFerQ7GbuhoieEXAyc9J1qURERES1Hn85sBo9q18OfPQKcwmGZiIiIqIn4y8HPmeczJywoNMCjbYFnRYwNBMRERFVIQbnOiC9IB0z/5qp0Tbzr5nlPm2DiIiIiLTH4FzLPbpMw83cDRtDNmqseWZ4JiIiIqoaDM612OOhOaJnBAIcAkrdMMjwTERERPT0GJxrMTMDM9iY2JS6EfDRp23YmNjAzMBMx5USERER1X58qkY1ehZP1ci7n4eC4oIybwRML0iHmYEZLAwtqmVuIiIiotpOm7ym/4xqompiYWhRbjDmUzWIiIiIqg6XahARERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREZEEDM5ERERERBIwOBMRERERScDgTEREREQkAYMzEREREelUXu4NpKcrytyWnq5AXu6NZ1tQORiciYiIiEhn8nJv4N2toRi+awjS005pbEtPO4Xhu4bg3a2hNSI8MzgTERERkc4UFN7CbVGM63Jg+B9D1eE5Pe0Uhv8xFNflwG1RjILCWzqulMGZiIiIiHTIySkAESEb4KaEOjwrzvygDs1uSiAiZAOcnAJ0XSqDMxERERHplpNzoEZ4HnJyoWZodg7UdYkAGJyJiIiIqAZwcg7EgjYzNNoWtJlRY0IzwOBMRERERDVAetopzDy+UKNt5vGFpW4Y1CUGZyIiIiLSqUdvBHRTAhtbztBY81xTwjODMxERERHpTHq6otSNgAEtBpe6YbC85zw/SwzORERERKQzZqb2sJEZlLoR8NEbBm1kBjAztddxpYBMCCF0XURdlZubCysrK+Tk5MDS0lLX5RARERHVSHm5N1BQeKvM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",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arch = GateBased(error_rate=1e-4, gate_time=100, measurement_time=500)\n",
    "\n",
    "# Litinski baseline (unscaled, should closely match built-in Litinski19Factory)\n",
    "litinski_baseline = SurfaceCode.q() * ScaledLitinskiFactory.q()\n",
    "\n",
    "# Compact factory: half the physical qubits\n",
    "compact = SurfaceCode.q() * ScaledLitinskiFactory.q(space_factor=0.5)\n",
    "\n",
    "# Fast factory: half the cycles\n",
    "fast = SurfaceCode.q() * ScaledLitinskiFactory.q(cycle_factor=0.5)\n",
    "\n",
    "results = [\n",
    "    estimate(app, arch, litinski_baseline, max_error=0.01, name=\"Litinski baseline\"),\n",
    "    estimate(app, arch, compact, max_error=0.01, name=\"Compact factory (0.5× space)\"),\n",
    "    estimate(app, arch, fast, max_error=0.01, name=\"Fast factory (0.5× cycles)\"),\n",
    "    baseline,\n",
    "]\n",
    "\n",
    "plot_estimates(results, figsize=(8, 5), runtime_unit=\"ms\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5da8f59",
   "metadata": {},
   "source": [
    "## Composing a full custom stack\n",
    "\n",
    "Now that we have all three custom layers, let's compose them into a complete\n",
    "estimation stack.  The `*` operator creates a Cartesian product over all\n",
    "hyperparameter configurations:\n",
    "\n",
    "- `GenericQEC` searches over code distances 3–21\n",
    "- `ScaledLitinskiFactory` produces multiple factory configurations from\n",
    "  the Litinski protocol table\n",
    "\n",
    "The estimator evaluates all combinations and returns only the Pareto-optimal\n",
    "results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "bba890f4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>qubits</th>\n",
       "      <th>runtime</th>\n",
       "      <th>error</th>\n",
       "      <th>physical_compute_qubits</th>\n",
       "      <th>physical_factory_qubits</th>\n",
       "      <th>physical_memory_qubits</th>\n",
       "      <th>factories</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Full custom stack</td>\n",
       "      <td>3151</td>\n",
       "      <td>0 days 00:00:00.000299</td>\n",
       "      <td>0.006790</td>\n",
       "      <td>3150</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1×T</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Full custom stack</td>\n",
       "      <td>9630</td>\n",
       "      <td>0 days 00:00:00.000292500</td>\n",
       "      <td>0.007312</td>\n",
       "      <td>3150</td>\n",
       "      <td>6480</td>\n",
       "      <td>0</td>\n",
       "      <td>8×T</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Full custom stack</td>\n",
       "      <td>13284</td>\n",
       "      <td>0 days 00:00:00.000183300</td>\n",
       "      <td>0.009416</td>\n",
       "      <td>1134</td>\n",
       "      <td>12150</td>\n",
       "      <td>0</td>\n",
       "      <td>15×T</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                name  qubits                   runtime     error  \\\n",
       "0  Full custom stack    3151    0 days 00:00:00.000299  0.006790   \n",
       "1  Full custom stack    9630 0 days 00:00:00.000292500  0.007312   \n",
       "2  Full custom stack   13284 0 days 00:00:00.000183300  0.009416   \n",
       "\n",
       "   physical_compute_qubits  physical_factory_qubits  physical_memory_qubits  \\\n",
       "0                     3150                        1                       0   \n",
       "1                     3150                     6480                       0   \n",
       "2                     1134                    12150                       0   \n",
       "\n",
       "  factories  \n",
       "0       1×T  \n",
       "1       8×T  \n",
       "2      15×T  "
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Full custom stack: custom architecture + custom QEC + custom factory\n",
    "custom_arch = ParameterizedArchitecture(\n",
    "    single_qubit_gate_time=100,\n",
    "    two_qubit_gate_time=200,\n",
    "    measurement_time=400,\n",
    "    single_qubit_error_rate=5e-5,\n",
    "    two_qubit_error_rate=1e-4,\n",
    "    measurement_error_rate=1e-4,\n",
    ")\n",
    "\n",
    "custom_results = estimate(\n",
    "    app, custom_arch,\n",
    "    isa_query=GenericQEC.q() * ScaledLitinskiFactory.q(),\n",
    "    max_error=0.01,\n",
    "    name=\"Full custom stack\",\n",
    ")\n",
    "\n",
    "custom_results.add_qubit_partition_column()\n",
    "custom_results.add_factory_summary_column()\n",
    "custom_results.as_frame()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ce953fa",
   "metadata": {},
   "source": [
    "> **Why does the first result show only 1 factory qubit?**\n",
    ">\n",
    "> When the physical T-gate error rate is low enough, the estimator may find that\n",
    "> it can meet the overall error budget *without* distillation, using the raw\n",
    "> physical T gate directly.  In that case the \"factory\" is just a single physical\n",
    "> qubit producing T states one at a time, which is why the qubit count is so\n",
    "> small.  The trade-off is a much longer runtime (thousands of serial T-gate\n",
    "> executions instead of a few batched factory runs).  Subsequent rows in the\n",
    "> table use the `ScaledLitinskiFactory` and show the more typical pattern of\n",
    "> dedicating thousands of physical qubits to a distillation factory in exchange\n",
    "> for faster execution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c65d0684",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "plot_estimates([custom_results, baseline], figsize=(8, 5), runtime_unit=\"ms\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae29b99a",
   "metadata": {},
   "source": [
    "## Key takeaways\n",
    "\n",
    "1. **Three extension points.** The estimator's model stack has three layers:\n",
    "   `Architecture`, QEC `ISATransform`, and factory `ISATransform`, each of\n",
    "   which can be replaced independently.\n",
    "\n",
    "2. **Implement two methods.** Every custom QEC or factory model is a dataclass\n",
    "   that implements `required_isa` (what physical instructions it needs) and\n",
    "   `provided_isa` (what logical instructions it provides, with resource\n",
    "   formulas).  A custom architecture implements only `provided_isa`.\n",
    "\n",
    "3. **Automatic search.** Mark hyperparameters as `KW_ONLY` fields with a\n",
    "   `metadata={\"domain\": ...}` and the estimator searches over them\n",
    "   automatically, keeping only the Pareto-optimal configurations.\n",
    "\n",
    "4. **Mix and match.** Custom models compose freely with built-in ones using the\n",
    "   `*` operator.  You can replace one layer while keeping the others at their\n",
    "   defaults, which is useful for isolating the effect of a single modeling choice.\n",
    "\n",
    "5. **Provenance tracking.** Pass `transform=self` and `source=[...]` when\n",
    "   adding instructions to preserve the link between physical and logical\n",
    "   instructions.  This lets you inspect the full derivation chain in the\n",
    "   results (see [Analysing Results](2_analysing_results.ipynb))."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}