diff --git a/doc/getting_started.ipynb b/doc/getting_started.ipynb
index 35a20ecf..b976689e 100644
--- a/doc/getting_started.ipynb
+++ b/doc/getting_started.ipynb
@@ -1,111 +1,76 @@
{
+ "metadata": {
+ "kernelspec": {
+ "name": "python",
+ "display_name": "Python (Pyodide)",
+ "language": "python"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "python",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8"
+ },
+ "colab": {
+ "provenance": []
+ }
+ },
+ "nbformat_minor": 4,
+ "nbformat": 4,
"cells": [
{
"cell_type": "markdown",
+ "source": "
\n
Welcome to the Stim tutorial!
\n\nThis Jupyter notebook is a tutorial for [Stim](https://github.com/quantumlib/stim), a tool for high-performance simulation and analysis of quantum stabilizer circuits. You can run this notebook in your browser using [Google Colab](https://colab.google/), or download it to your computer and run it using [Jupyter](https://docs.jupyter.org/en/latest/running.html).\n",
"metadata": {
"id": "7vg1S92NEAXs"
- },
- "source": [
- "
\n",
- "Welcome to the Stim tutorial!
\n",
- "\n",
- "This Jupyter notebook is a tutorial for [Stim](https://github.com/quantumlib/stim), a tool for high-performance simulation and analysis of quantum stabilizer circuits. You can run this notebook in your browser using [Google Colab](https://colab.google/), or download it to your computer and run it using [Jupyter](https://docs.jupyter.org/en/latest/running.html).\n"
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "# Table of contents\n\n0. [Prerequisites](#prerequisites)\n1. [What is Stim?](#what-is-stim)\n2. [Copy and use this Jupyter/Colab notebook](#using-this-notebook)\n3. [Install the `stim` Python package](#install-stim)\n4. [Create a simple circuit, and sample from it](#make-circuit)\n5. [Add detector annotations to a circuit, and sample them](#sample-detectors)\n6. [Generate example error correction circuits](#make-qec-circuits)\n7. [Use `pymatching` to correct errors in a circuit](#use-pymatching)\n8. [Estimate the threshold of a repetition code using Monte Carlo sampling](#rep-code)\n9. [Use `sinter` to streamline the Monte Carlo sampling process](#use-sinter)\n10. [Estimate the threshold and footprint of a surface code](#surface-code)\n11. [Conclusion](#end-of-tutorial)\n12. [Additional resources](#additional-resources)",
"metadata": {
"id": "0V2LXIBKKqA9"
- },
- "source": [
- "# Table of contents\n",
- "\n",
- "0. [Prerequisites](#prerequisites)\n",
- "1. [What is Stim?](#what-is-stim)\n",
- "2. [Copy and use this Jupyter/Colab notebook](#using-this-notebook)\n",
- "3. [Install the `stim` Python package](#install-stim)\n",
- "4. [Create a simple circuit, and sample from it](#make-circuit)\n",
- "5. [Add detector annotations to a circuit, and sample them](#sample-detectors)\n",
- "6. [Generate example error correction circuits](#make-qec-circuits)\n",
- "7. [Use `pymatching` to correct errors in a circuit](#use-pymatching)\n",
- "8. [Estimate the threshold of a repetition code using Monte Carlo sampling](#rep-code)\n",
- "9. [Use `sinter` to streamline the Monte Carlo sampling process](#use-sinter)\n",
- "10. [Estimate the threshold and footprint of a surface code](#surface-code)\n",
- "11. [Conclusion](#end-of-tutorial)\n",
- "12. [Additional resources](additional-resources)"
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 0. Prerequisites\n\nTo get the most out of this tutorial, it's helpful to have the following background:\n\n- Familiarity with basic Python syntax, and having a working Python 3.7+ environment. (Perhaps you are reading this notebook in such an environment.)\n\n- Familiarity with the basic concepts of *quantum circuits*, such as qubits and common quantum gates like [Hadamard](https://en.wikipedia.org/wiki/Quantum_logic_gate#Hadamard_gate) and [CNOT](https://en.wikipedia.org/wiki/Quantum_logic_gate#Controlled_gates).\n\n- A basic understanding of stabilizer circuits. For example, this tutorial assumes you've heard that they can be simulated cheaply and that they can represent protocols such as quantum error correction.\n\n- *Some* familiarity with quantum error-correcting codes. For example, this tutorial assumes that you've heard the terms \"surface code\" and \"threshold\".\n\nIf you don't have these prerequisites yet, take a look at the [additional resources](additional-resources) at the end of this tutorial for suggestions about how to learn more.",
"metadata": {
"id": "43rMSrBhKtyX"
- },
- "source": [
- "\n",
- "# 0. Prerequisites\n",
- "\n",
- "To get the most out of this tutorial, it's helpful to have the following background:\n",
- "\n",
- "- Familiarity with basic Python syntax, and having a working Python 3.7+ environment. (Perhaps you are reading this notebook in such an environment.)\n",
- "\n",
- "- Familiarity with the basic concepts of *quantum circuits*, such as qubits and common quantum gates like [Hadamard](https://en.wikipedia.org/wiki/Quantum_logic_gate#Hadamard_gate) and [CNOT](https://en.wikipedia.org/wiki/Quantum_logic_gate#Controlled_gates).\n",
- "\n",
- "- A basic understanding of stabilizer circuits. For example, this tutorial assumes you've heard that they can be simulated cheaply and that they can represent protocols such as quantum error correction.\n",
- "\n",
- "- *Some* familiarity with quantum error-correcting codes. For example, this tutorial assumes that you've heard the terms \"surface code\" and \"threshold\".\n",
- "\n",
- "If you don't have these prerequisites yet, take a look at the [additional resources](additional-resources) at the end of this tutorial for suggestions about how to learn more."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 1. What is Stim?\n\nStim is an [open-source tool](https://github.com/quantumlib/Stim) for high-performance analysis and simulation of quantum stabilizer circuits, with a focus on quantum error correction circuits.\n\nHere is a plot from the [paper introducing Stim](https://doi.org/10.22331/q-2021-07-06-497), showing that Stim is thousands of times faster than other tools at sampling stabilizer circuits:\n\n\n\nIn addition to fast simulation, Stim provides general utilities for editing, inspecting, and transforming stabilizer circuits. In particular, Stim can automatically derive a matching graph from a stabilizer circuit annotated with detectors and noise channels.",
"metadata": {
- "id": "ulLKqhVxmfxr",
- "jp-MarkdownHeadingCollapsed": true
- },
- "source": [
- "\n",
- "# 1. What is Stim?\n",
- "\n",
- "Stim is an [open-source tool](https://github.com/quantumlib/Stim) for high-performance analysis and simulation of quantum stabilizer circuits, with a focus on quantum error correction circuits.\n",
- "\n",
- "Here is a plot from the [paper introducing Stim](https://doi.org/10.22331/q-2021-07-06-497), showing that Stim is thousands of times faster than other tools at sampling stabilizer circuits:\n",
- "\n",
- "\n",
- "\n",
- "In addition to fast simulation, Stim provides general utilities for editing, inspecting, and transforming stabilizer circuits. In particular, Stim can automatically derive a matching graph from a stabilizer circuit annotated with detectors and noise channels."
- ]
+ "id": "ulLKqhVxmfxr"
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 2. Install the Stim python package\n\nThe first thing to do is to install and import Stim.\nThanks to the Python ecosystem, this is easy to do!\nStim is available as a [PyPI](https://pypi.org/project/stim/) package, and can be installed using `pip install stim` and then imported with `import stim` (just like any other Python package).",
"metadata": {
"id": "fh8rot1PYyDh"
- },
- "source": [
- "\n",
- "# 2. Install the Stim python package\n",
- "\n",
- "The first thing to do is to install and import Stim.\n",
- "Thanks to the Python ecosystem, this is easy to do!\n",
- "Stim is available as a [PyPI](https://pypi.org/project/stim/) package, and can be installed using `pip install stim` and then imported with `import stim` (just like any other Python package)."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "!pip install stim~=1.14\n!pip install numpy~=1.0 # 1.0 instead of 2.0 for pymatching compatibility later\n!pip install scipy",
"metadata": {
"id": "fMf_vlB7D6fR"
},
"outputs": [],
- "source": [
- "!pip install stim~=1.14\n",
- "!pip install numpy~=1.0 # 1.0 instead of 2.0 for pymatching compatibility later\n",
- "!pip install scipy"
- ]
+ "execution_count": null
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "import stim\nprint(stim.__version__)",
"metadata": {
"id": "P0lD6ilJD8Pi",
"outputId": "79a7cd42-9677-46f7-df1e-1cd4a518f601"
@@ -114,62 +79,37 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "1.14.0\n"
- ]
+ "text": "1.14.0\n"
}
],
- "source": [
- "import stim\n",
- "print(stim.__version__)"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "\n# 3. Create a simple circuit, and sample from it\n\nIn Stim, circuits are instances of the [`stim.Circuit`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit) class. You create a new empty circuit with `stim.Circuit()`, and add operations to it by calling `circuit.append(name_of_gate, list_of_targets)`.\n\nYou can find the name of the gate you want from the [Stim gates reference](https://github.com/quantumlib/Stim/blob/main/doc/gates.md). Most of the names are straightforward, like \"H\" for the Hadamard gate. A *target* is just a number representing the identity of a qubit. There's a qubit `0`, a qubit `1`, etc.\n\nThe first circuit you'll make is a circuit that prepares a [Bell pair](https://en.wikipedia.org/wiki/Bell_state) and then measures it:",
"metadata": {
"id": "vah6-5YpGdaG"
- },
- "source": [
- "\n",
- "# 3. Create a simple circuit, and sample from it\n",
- "\n",
- "In Stim, circuits are instances of the [`stim.Circuit`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit) class. You create a new empty circuit with `stim.Circuit()`, and add operations to it by calling `circuit.append(name_of_gate, list_of_targets)`.\n",
- "\n",
- "You can find the name of the gate you want from the [Stim gates reference](https://github.com/quantumlib/Stim/blob/main/doc/gates.md). Most of the names are straightforward, like \"H\" for the Hadamard gate. A *target* is just a number representing the identity of a qubit. There's a qubit `0`, a qubit `1`, etc.\n",
- "\n",
- "The first circuit you'll make is a circuit that prepares a [Bell pair](https://en.wikipedia.org/wiki/Bell_state) and then measures it:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit = stim.Circuit()\n\n# First, the circuit will initialize a Bell pair.\ncircuit.append(\"H\", [0])\ncircuit.append(\"CNOT\", [0, 1])\n\n# Then, the circuit will measure both qubits of the Bell pair in the Z basis.\ncircuit.append(\"M\", [0, 1])",
"metadata": {
"id": "UP84FdeWGodO"
},
"outputs": [],
- "source": [
- "circuit = stim.Circuit()\n",
- "\n",
- "# First, the circuit will initialize a Bell pair.\n",
- "circuit.append(\"H\", [0])\n",
- "circuit.append(\"CNOT\", [0, 1])\n",
- "\n",
- "# Then, the circuit will measure both qubits of the Bell pair in the Z basis.\n",
- "circuit.append(\"M\", [0, 1])"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Stim has a few ways to let you look at the circuits you've made. The circuit's `repr` is an expression that recreates the circuit using [Stim's circuit file syntax](https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md):",
"metadata": {
"id": "ySG_dqfQ-qOQ"
- },
- "source": [
- "Stim has a few ways to let you look at the circuits you've made. The circuit's `repr` is an expression that recreates the circuit using [Stim's circuit file syntax](https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md):"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -193,22 +133,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "circuit"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can also use the [`circuit.diagram`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.diagram) method to get an annotated text diagram of the circuit:",
"metadata": {
"id": "D-RpRUTw-qOQ"
- },
- "source": [
- "You can also use the [`circuit.diagram`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.diagram) method to get an annotated text diagram of the circuit:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit.diagram()",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -235,22 +171,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "circuit.diagram()"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "There are also other types of diagrams. For example, specifying `timeline-svg` will return a Scalable Vector Graphics ([SVG](https://en.wikipedia.org/wiki/SVG)) picture of the circuit instead of a text diagram:",
"metadata": {
"id": "XKnYuBEB-qOQ"
- },
- "source": [
- "There are also other types of diagrams. For example, specifying `timeline-svg` will return a Scalable Vector Graphics ([SVG](https://en.wikipedia.org/wiki/SVG)) picture of the circuit instead of a text diagram:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit.diagram('timeline-svg')",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -311,24 +243,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "circuit.diagram('timeline-svg')"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Anyways, let's stop looking at your circuit and start using it. You can sample from the circuit by using the [`circuit.compile_sampler()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_sampler) method to get a sampler object, and then calling `sample` on that object.\n\nTry taking 10 shots from the circuit:",
"metadata": {
"id": "5dRl_-WZHDP2"
- },
- "source": [
- "Anyways, let's stop looking at your circuit and start using it. You can sample from the circuit by using the [`circuit.compile_sampler()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_sampler) method to get a sampler object, and then calling `sample` on that object.\n",
- "\n",
- "Try taking 10 shots from the circuit:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "sampler = circuit.compile_sampler()\nprint(sampler.sample(shots=10))",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -340,56 +266,28 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "[[False False]\n",
- " [ True True]\n",
- " [False False]\n",
- " [False False]\n",
- " [ True True]\n",
- " [False False]\n",
- " [ True True]\n",
- " [False False]\n",
- " [False False]\n",
- " [ True True]]\n"
- ]
+ "text": "[[False False]\n, [ True True]\n, [False False]\n, [False False]\n, [ True True]\n, [False False]\n, [ True True]\n, [False False]\n, [False False]\n, [ True True]]\n"
}
],
- "source": [
- "sampler = circuit.compile_sampler()\n",
- "print(sampler.sample(shots=10))"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Notice how there are ten rows (because you took ten shots), with two results per row (because there were two measurements in the circuit).\nAlso notice how the results are random from row to row, but always agree within each row.\nThat makes sense; that's what's supposed to happen when you repeatedly prepare and measure the |00⟩ + |11⟩ state.",
"metadata": {
"id": "D5KUSysIJB5g"
- },
- "source": [
- "Notice how there are ten rows (because you took ten shots), with two results per row (because there were two measurements in the circuit).\n",
- "Also notice how the results are random from row to row, but always agree within each row.\n",
- "That makes sense; that's what's supposed to happen when you repeatedly prepare and measure the |00⟩ + |11⟩ state."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 4. Add detector annotations to a circuit, and sample them\n\nStim circuits can include error-correction annotations.\nIn particular, you can annotate that certain sets of measurements can be used to detect errors.\nFor example, in the circuit you created above, the two measurement results should always be equal.\nYou can tell Stim you care about that by adding a `DETECTOR` annotation to the circuit.\n\nThe `DETECTOR` annotation will take two targets: the two measurements whose parity you are asserting should be consistent from run to run. You point at the measurements by using the [`stim.target_rec`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.target_rec) method (short for \"target measurement record\"). The most recent measurement is `stim.target_rec(-1)` (also known as `rec[-1]` in Stim's circuit language), and the second most recent measurement is `stim.target_rec(-2)`:",
"metadata": {
"id": "zX7ZyHVAHfF_"
- },
- "source": [
- "\n",
- "# 4. Add detector annotations to a circuit, and sample them\n",
- "\n",
- "Stim circuits can include error-correction annotations.\n",
- "In particular, you can annotate that certain sets of measurements can be used to detect errors.\n",
- "For example, in the circuit you created above, the two measurement results should always be equal.\n",
- "You can tell Stim you care about that by adding a `DETECTOR` annotation to the circuit.\n",
- "\n",
- "The `DETECTOR` annotation will take two targets: the two measurements whose parity you are asserting should be consistent from run to run. You point at the measurements by using the [`stim.target_rec`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.target_rec) method (short for \"target measurement record\"). The most recent measurement is `stim.target_rec(-1)` (also known as `rec[-1]` in Stim's circuit language), and the second most recent measurement is `stim.target_rec(-2)`:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "# Indicate the two previous measurements are supposed to consistently agree.\ncircuit.append(\"DETECTOR\", [stim.target_rec(-1), stim.target_rec(-2)])\nprint(repr(circuit))",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -401,39 +299,21 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "stim.Circuit('''\n",
- " H 0\n",
- " CX 0 1\n",
- " M 0 1\n",
- " DETECTOR rec[-1] rec[-2]\n",
- "''')\n"
- ]
+ "text": "stim.Circuit('''\n, H 0\n, CX 0 1\n, M 0 1\n, DETECTOR rec[-1] rec[-2]\n,''')\n"
}
],
- "source": [
- "# Indicate the two previous measurements are supposed to consistently agree.\n",
- "circuit.append(\"DETECTOR\", [stim.target_rec(-1), stim.target_rec(-2)])\n",
- "print(repr(circuit))"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "A slightly subtle point about detectors is that they only assert that the parity of the measurements is *always the same under noiseless execution*.\nA detector doesn't say whether the parity should be even or should be odd, only that it should always be the same.\nYou annotate that a pair of measurements is always different in the same way that you annotate that a pair of measurements is always the same; it's the *consistency* that's key.\n\nMoving on, now that you've annotated the circuit with a detector, you can sample from the circuit's detectors instead of sampling from its measurements.\nYou do that by creating a detector sampler, using the [`compile_detector_sampler`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_detector_sampler) method, and then calling [`sample`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.CompiledDetectorSampler.sample) on it.",
"metadata": {
"id": "tEz4G3OjI164"
- },
- "source": [
- "A slightly subtle point about detectors is that they only assert that the parity of the measurements is *always the same under noiseless execution*.\n",
- "A detector doesn't say whether the parity should be even or should be odd, only that it should always be the same.\n",
- "You annotate that a pair of measurements is always different in the same way that you annotate that a pair of measurements is always the same; it's the *consistency* that's key.\n",
- "\n",
- "Moving on, now that you've annotated the circuit with a detector, you can sample from the circuit's detectors instead of sampling from its measurements.\n",
- "You do that by creating a detector sampler, using the [`compile_detector_sampler`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_detector_sampler) method, and then calling [`sample`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.CompiledDetectorSampler.sample) on it."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "sampler = circuit.compile_detector_sampler()\nprint(sampler.sample(shots=5))",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -445,76 +325,37 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "[[False]\n",
- " [False]\n",
- " [False]\n",
- " [False]\n",
- " [False]]\n"
- ]
+ "text": "[[False]\n, [False]\n, [False]\n, [False]\n, [False]]\n"
}
],
- "source": [
- "sampler = circuit.compile_detector_sampler()\n",
- "print(sampler.sample(shots=5))"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "There are 5 rows in the results, because you took 5 shots.\nThere's one entry per row, because you put one detector in the circuit.\n\nNotice how the results are always `False`.\nThis means the detector is never producing a detection event.\nThat's because there's no noise in the circuit; nothing to disturb the peace and quiet of a perfectly working machine.\nWell... time to fix that!\n\nStim has a variety of error channels to pick from, like single qubit depolarization (`DEPOLARIZE1`) and phase damping (`Z_ERROR`), but in this context a good error to try is `X_ERROR`.\nThe `X_ERROR` noise channel probabilistically applies a bit flip (a Pauli X error) to each of its targets.\nNote that each target is operated on independently.\nThey don't all flip together with the given probability, each one flips individually with the given probability.\n\nYou can recreate the circuit, with the noise inserted, by using Stim's domain specific language for circuits. While you're at it, throw in some `TICK` instructions to indicate the progression of time:",
"metadata": {
"id": "kCby-NA4Jevl"
- },
- "source": [
- "There are 5 rows in the results, because you took 5 shots.\n",
- "There's one entry per row, because you put one detector in the circuit.\n",
- "\n",
- "Notice how the results are always `False`.\n",
- "This means the detector is never producing a detection event.\n",
- "That's because there's no noise in the circuit; nothing to disturb the peace and quiet of a perfectly working machine.\n",
- "Well... time to fix that!\n",
- "\n",
- "Stim has a variety of error channels to pick from, like single qubit depolarization (`DEPOLARIZE1`) and phase damping (`Z_ERROR`), but in this context a good error to try is `X_ERROR`.\n",
- "The `X_ERROR` noise channel probabilistically applies a bit flip (a Pauli X error) to each of its targets.\n",
- "Note that each target is operated on independently.\n",
- "They don't all flip together with the given probability, each one flips individually with the given probability.\n",
- "\n",
- "You can recreate the circuit, with the noise inserted, by using Stim's domain specific language for circuits. While you're at it, throw in some `TICK` instructions to indicate the progression of time:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit = stim.Circuit(\"\"\"\n H 0\n TICK\n\n CX 0 1\n X_ERROR(0.2) 0 1\n TICK\n\n M 0 1\n DETECTOR rec[-1] rec[-2]\n\"\"\")",
"metadata": {
"id": "HniubUFXJ9jh"
},
"outputs": [],
- "source": [
- "circuit = stim.Circuit(\"\"\"\n",
- " H 0\n",
- " TICK\n",
- "\n",
- " CX 0 1\n",
- " X_ERROR(0.2) 0 1\n",
- " TICK\n",
- "\n",
- " M 0 1\n",
- " DETECTOR rec[-1] rec[-2]\n",
- "\"\"\")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Thanks to adding the `TICK` instructions, you get access to a new type of diagram: `timeslice-svg`.\nThis diagram shows the operations from each tick in a separate frame:",
"metadata": {
"id": "U7_2QfyiKSBL"
- },
- "source": [
- "Thanks to adding the `TICK` instructions, you get access to a new type of diagram: `timeslice-svg`.\n",
- "This diagram shows the operations from each tick in a separate frame:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit.diagram('timeslice-svg')",
"metadata": {
"id": "1jOOCijd-qOR",
"outputId": "44ff0bba-086b-4846-faa9-1dc4549c6b78"
@@ -600,22 +441,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "circuit.diagram('timeslice-svg')"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Now that you've added some noise, try sampling some more detector shots and see what happens:",
"metadata": {
"id": "7lBUrusk-qOR"
- },
- "source": [
- "Now that you've added some noise, try sampling some more detector shots and see what happens:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "sampler = circuit.compile_detector_sampler()\nprint(sampler.sample(shots=10))",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -627,43 +464,21 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "[[False]\n",
- " [False]\n",
- " [ True]\n",
- " [ True]\n",
- " [False]\n",
- " [False]\n",
- " [ True]\n",
- " [ True]\n",
- " [ True]\n",
- " [False]]\n"
- ]
+ "text": "[[False]\n, [False]\n, [ True]\n, [ True]\n, [False]\n, [False]\n, [ True]\n, [ True]\n, [ True]\n, [False]]\n"
}
],
- "source": [
- "sampler = circuit.compile_detector_sampler()\n",
- "print(sampler.sample(shots=10))"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "It's no longer all `False`s (unless you got very lucky).\nThere are `True`s appearing amongst the `False`s.\n\nThe *detection fraction* of the circuit is how often detectors fire on average.\nGiven that an X error is being applied to each qubit with 20% probability, and the detector will fire when one of the qubits is hit (but not both), the detection fraction of the detectors in this circuit is $0.8 \\cdot 0.2 \\cdot 2 = 0.32$.\n\nYou can estimate the detection fraction by just taking a lot of shots, and dividing by the number of shots and the number of detectors:",
"metadata": {
"id": "AreMncCeKb1x"
- },
- "source": [
- "It's no longer all `False`s (unless you got very lucky).\n",
- "There are `True`s appearing amongst the `False`s.\n",
- "\n",
- "The *detection fraction* of the circuit is how often detectors fire on average.\n",
- "Given that an X error is being applied to each qubit with 20% probability, and the detector will fire when one of the qubits is hit (but not both), the detection fraction of the detectors in this circuit is $0.8 \\cdot 0.2 \\cdot 2 = 0.32$.\n",
- "\n",
- "You can estimate the detection fraction by just taking a lot of shots, and dividing by the number of shots and the number of detectors:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "import numpy as np\nprint(np.sum(sampler.sample(shots=10**6)) / 10**6)",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -675,52 +490,28 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "0.320135\n"
- ]
+ "text": "0.320135\n"
}
],
- "source": [
- "import numpy as np\n",
- "print(np.sum(sampler.sample(shots=10**6)) / 10**6)"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "As you can see, the sampled estimate ends up close to the expected value $0.32$.",
"metadata": {
"id": "RKM6PLk8Tl13"
- },
- "source": [
- "As you can see, the sampled estimate ends up close to the expected value $0.32$."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 5. Generate example error correction circuits\n\nNow it's time for you to work with a *real* error-correcting circuit.\nWell... a classical error-correcting circuit:\nthe *repetition* code.\n\nYou could generate a repetition code circuit for yourself, but for the purposes of this tutorial it's easiest to use the example included with Stim.\nYou can do this by calling [`stim.Circuit.generated`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.generated) with an argument of `\"repetition_code:memory\"`.\n(You can find out about other valid arguments in the method's doc string, or just by passing in a bad one and looking at the exception message that comes out.)\n\nStim takes a few different parameters when generating circuits.\nYou have to decide how many times the stabilizers of the code are measured by specifying `rounds`, you have to decide on the size of the code by specifying `distance`, and you can specify what kind of noise to include using a few optional parameters.\n\nTo start with, just set `before_round_data_depolarization=0.04` and `before_measure_flip_probability=0.01`. This will insert a `DEPOLARIZE1(0.04)` operation at the start of each round targeting every data qubit, and an `X_ERROR(0.01)` just before each measurement operation.\nThis is a \"phenomenological noise model\".",
"metadata": {
"id": "fG2jQsH2LZQP"
- },
- "source": [
- "\n",
- "# 5. Generate example error correction circuits\n",
- "\n",
- "Now it's time for you to work with a *real* error-correcting circuit.\n",
- "Well... a classical error-correcting circuit:\n",
- "the *repetition* code.\n",
- "\n",
- "You could generate a repetition code circuit for yourself, but for the purposes of this tutorial it's easiest to use the example included with Stim.\n",
- "You can do this by calling [`stim.Circuit.generated`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.generated) with an argument of `\"repetition_code:memory\"`.\n",
- "(You can find out about other valid arguments in the method's doc string, or just by passing in a bad one and looking at the exception message that comes out.)\n",
- "\n",
- "Stim takes a few different parameters when generating circuits.\n",
- "You have to decide how many times the stabilizers of the code are measured by specifying `rounds`, you have to decide on the size of the code by specifying `distance`, and you can specify what kind of noise to include using a few optional parameters.\n",
- "\n",
- "To start with, just set `before_round_data_depolarization=0.04` and `before_measure_flip_probability=0.01`. This will insert a `DEPOLARIZE1(0.04)` operation at the start of each round targeting every data qubit, and an `X_ERROR(0.01)` just before each measurement operation.\n",
- "This is a \"phenomenological noise model\"."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit = stim.Circuit.generated(\n \"repetition_code:memory\",\n rounds=25,\n distance=9,\n before_round_data_depolarization=0.04,\n before_measure_flip_probability=0.01)\n\nprint(repr(circuit))\ncircuit.diagram('timeline-svg')",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -732,57 +523,7 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "stim.Circuit('''\n",
- " R 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\n",
- " TICK\n",
- " DEPOLARIZE1(0.04) 0 2 4 6 8 10 12 14 16\n",
- " CX 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n",
- " TICK\n",
- " CX 2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15\n",
- " TICK\n",
- " X_ERROR(0.01) 1 3 5 7 9 11 13 15\n",
- " MR 1 3 5 7 9 11 13 15\n",
- " DETECTOR(1, 0) rec[-8]\n",
- " DETECTOR(3, 0) rec[-7]\n",
- " DETECTOR(5, 0) rec[-6]\n",
- " DETECTOR(7, 0) rec[-5]\n",
- " DETECTOR(9, 0) rec[-4]\n",
- " DETECTOR(11, 0) rec[-3]\n",
- " DETECTOR(13, 0) rec[-2]\n",
- " DETECTOR(15, 0) rec[-1]\n",
- " REPEAT 24 {\n",
- " TICK\n",
- " DEPOLARIZE1(0.04) 0 2 4 6 8 10 12 14 16\n",
- " CX 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n",
- " TICK\n",
- " CX 2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15\n",
- " TICK\n",
- " X_ERROR(0.01) 1 3 5 7 9 11 13 15\n",
- " MR 1 3 5 7 9 11 13 15\n",
- " SHIFT_COORDS(0, 1)\n",
- " DETECTOR(1, 0) rec[-8] rec[-16]\n",
- " DETECTOR(3, 0) rec[-7] rec[-15]\n",
- " DETECTOR(5, 0) rec[-6] rec[-14]\n",
- " DETECTOR(7, 0) rec[-5] rec[-13]\n",
- " DETECTOR(9, 0) rec[-4] rec[-12]\n",
- " DETECTOR(11, 0) rec[-3] rec[-11]\n",
- " DETECTOR(13, 0) rec[-2] rec[-10]\n",
- " DETECTOR(15, 0) rec[-1] rec[-9]\n",
- " }\n",
- " X_ERROR(0.01) 0 2 4 6 8 10 12 14 16\n",
- " M 0 2 4 6 8 10 12 14 16\n",
- " DETECTOR(1, 1) rec[-8] rec[-9] rec[-17]\n",
- " DETECTOR(3, 1) rec[-7] rec[-8] rec[-16]\n",
- " DETECTOR(5, 1) rec[-6] rec[-7] rec[-15]\n",
- " DETECTOR(7, 1) rec[-5] rec[-6] rec[-14]\n",
- " DETECTOR(9, 1) rec[-4] rec[-5] rec[-13]\n",
- " DETECTOR(11, 1) rec[-3] rec[-4] rec[-12]\n",
- " DETECTOR(13, 1) rec[-2] rec[-3] rec[-11]\n",
- " DETECTOR(15, 1) rec[-1] rec[-2] rec[-10]\n",
- " OBSERVABLE_INCLUDE(0) rec[-1]\n",
- "''')\n"
- ]
+ "text": "stim.Circuit('''\n, R 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\n, TICK\n, DEPOLARIZE1(0.04) 0 2 4 6 8 10 12 14 16\n, CX 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n, TICK\n, CX 2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15\n, TICK\n, X_ERROR(0.01) 1 3 5 7 9 11 13 15\n, MR 1 3 5 7 9 11 13 15\n, DETECTOR(1, 0) rec[-8]\n, DETECTOR(3, 0) rec[-7]\n, DETECTOR(5, 0) rec[-6]\n, DETECTOR(7, 0) rec[-5]\n, DETECTOR(9, 0) rec[-4]\n, DETECTOR(11, 0) rec[-3]\n, DETECTOR(13, 0) rec[-2]\n, DETECTOR(15, 0) rec[-1]\n, REPEAT 24 {\n, TICK\n, DEPOLARIZE1(0.04) 0 2 4 6 8 10 12 14 16\n, CX 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n, TICK\n, CX 2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15\n, TICK\n, X_ERROR(0.01) 1 3 5 7 9 11 13 15\n, MR 1 3 5 7 9 11 13 15\n, SHIFT_COORDS(0, 1)\n, DETECTOR(1, 0) rec[-8] rec[-16]\n, DETECTOR(3, 0) rec[-7] rec[-15]\n, DETECTOR(5, 0) rec[-6] rec[-14]\n, DETECTOR(7, 0) rec[-5] rec[-13]\n, DETECTOR(9, 0) rec[-4] rec[-12]\n, DETECTOR(11, 0) rec[-3] rec[-11]\n, DETECTOR(13, 0) rec[-2] rec[-10]\n, DETECTOR(15, 0) rec[-1] rec[-9]\n, }\n, X_ERROR(0.01) 0 2 4 6 8 10 12 14 16\n, M 0 2 4 6 8 10 12 14 16\n, DETECTOR(1, 1) rec[-8] rec[-9] rec[-17]\n, DETECTOR(3, 1) rec[-7] rec[-8] rec[-16]\n, DETECTOR(5, 1) rec[-6] rec[-7] rec[-15]\n, DETECTOR(7, 1) rec[-5] rec[-6] rec[-14]\n, DETECTOR(9, 1) rec[-4] rec[-5] rec[-13]\n, DETECTOR(11, 1) rec[-3] rec[-4] rec[-12]\n, DETECTOR(13, 1) rec[-2] rec[-3] rec[-11]\n, DETECTOR(15, 1) rec[-1] rec[-2] rec[-10]\n, OBSERVABLE_INCLUDE(0) rec[-1]\n,''')\n"
},
{
"data": {
@@ -1828,40 +1569,25 @@
"output_type": "execute_result"
}
],
- "source": [
- "circuit = stim.Circuit.generated(\n",
- " \"repetition_code:memory\",\n",
- " rounds=25,\n",
- " distance=9,\n",
- " before_round_data_depolarization=0.04,\n",
- " before_measure_flip_probability=0.01)\n",
- "\n",
- "print(repr(circuit))\n",
- "circuit.diagram('timeline-svg')"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can see that this circuit is more complicated than the example you started with. Notice the little \"REP24\" at the bottom of the diagram. This circuit is using a `REPEAT` block to repeatedly measure the stabilizers of the code.",
"metadata": {
"id": "DEE3Vqq_ZzXP"
- },
- "source": [
- "You can see that this circuit is more complicated than the example you started with. Notice the little \"REP24\" at the bottom of the diagram. This circuit is using a `REPEAT` block to repeatedly measure the stabilizers of the code."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "With a circuit in hand, you can try sampling from it.\nTry sampling the measurements once, and printing out the results split up just right so that time advances from line to line:",
"metadata": {
"id": "lTu556AOMTv6"
- },
- "source": [
- "With a circuit in hand, you can try sampling from it.\n",
- "Try sampling the measurements once, and printing out the results split up just right so that time advances from line to line:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "sampler = circuit.compile_sampler()\none_sample = sampler.sample(shots=1)[0]\nfor k in range(0, len(one_sample), 8):\n timeslice = one_sample[k:k+8]\n print(\"\".join(\"1\" if e else \"_\" for e in timeslice))",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -1873,61 +1599,21 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "_______1\n",
- "________\n",
- "________\n",
- "________\n",
- "_______1\n",
- "_______1\n",
- "________\n",
- "________\n",
- "11_____1\n",
- "11___1_1\n",
- "11_____1\n",
- "11_____1\n",
- "11_____1\n",
- "11_11__1\n",
- "11_11__1\n",
- "11_11__1\n",
- "11_11__1\n",
- "1__11__1\n",
- "11_11__1\n",
- "1_111__1\n",
- "_11_1___\n",
- "1\n"
- ]
+ "text": "________\n,________\n,________\n,________\n,________\n,_______1\n,________\n,________\n,________\n,_______1\n,_______1\n,________\n,________\n,11_____1\n,11___1_1\n,11_____1\n,11_____1\n,11_____1\n,11_11__1\n,11_11__1\n,11_11__1\n,11_11__1\n,1__11__1\n,11_11__1\n,1_111__1\n,_11_1___\n,1\n"
}
],
- "source": [
- "sampler = circuit.compile_sampler()\n",
- "one_sample = sampler.sample(shots=1)[0]\n",
- "for k in range(0, len(one_sample), 8):\n",
- " timeslice = one_sample[k:k+8]\n",
- " print(\"\".join(\"1\" if e else \"_\" for e in timeslice))"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "See how the 1s seem to come in pairs of streaks?\nThat's because once a data qubit is flipped it stays flipped, and the measurements to its left and right permanently change parity.\n\nIf you sample the circuit's detectors, instead of its measurements, the streaks are replaced by spackle.\nYou get much sparser data:",
"metadata": {
"id": "I5J3W6bWOIhJ"
- },
- "source": [
- "See how the 1s seem to come in pairs of streaks?\n",
- "That's because once a data qubit is flipped it stays flipped, and the measurements to its left and right permanently change parity.\n",
- "\n",
- "If you sample the circuit's detectors, instead of its measurements, the streaks are replaced by spackle.\n",
- "You get much sparser data:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "detector_sampler = circuit.compile_detector_sampler()\none_sample = detector_sampler.sample(shots=1)[0]\nfor k in range(0, len(one_sample), 8):\n timeslice = one_sample[k:k+8]\n print(\"\".join(\"!\" if e else \"_\" for e in timeslice))",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -1939,71 +1625,21 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "_____!!_\n",
- "____!!__\n",
- "_____!!_\n",
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "________\n",
- "___!_!__\n",
- "_____!!_\n",
- "!!______\n",
- "!_______\n",
- "!_______\n",
- "________\n",
- "________\n",
- "___!!___\n",
- "________\n",
- "________\n"
- ]
+ "text": "________\n,________\n,________\n,________\n,________\n,________\n,_____!!_\n,____!!__\n,_____!!_\n,________\n,________\n,________\n,________\n,________\n,________\n,________\n,___!_!__\n,_____!!_\n,!!______\n,!_______\n,!_______\n,________\n,________\n,___!!___\n,________\n,________\n"
}
],
- "source": [
- "detector_sampler = circuit.compile_detector_sampler()\n",
- "one_sample = detector_sampler.sample(shots=1)[0]\n",
- "for k in range(0, len(one_sample), 8):\n",
- " timeslice = one_sample[k:k+8]\n",
- " print(\"\".join(\"!\" if e else \"_\" for e in timeslice))"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Notice how the `!`s tend to come in pairs, except near the sides.\nThis \"comes in pairs\" property is extremely important, because it allows you to perform error correction.\nEvery `!` must be paired with another `!`, with the left boundary, or with the right boundary.\nIn the circuit generated by Stim, the logical observable is annotated to be a measurement of the leftmost data qubit.\nThat data qubit was flipped once for each `!` that's paired with the left boundary.\nIf the data qubit was flipped an even number of times, the observable that was measured is correct.\nIf it was flipped an odd number of times, the observable that was measured needs to be flipped to be correct.\nIf you just had a syndrome decoder, you could use it to solve the matching problem and figure out if the leftmost data qubit (and therefore the protected logical observable) ended up flipped or not...\n\n\n# 6. Use `pymatching` to correct errors in a circuit\n\nStim has a key feature that makes it easier to use a decoder: converting a circuit into a detector error model.\nA detector error model is just a list of all the independent error mechanisms in a circuit, as well as their symptoms (which detectors they set off) and frame changes (which logical observables they flip).\n\nYou can get the detector error mode for a circuit by calling [`circuit.detector_error_model()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.detector_error_model):",
"metadata": {
"id": "fFNsm0_GOh4H"
- },
- "source": [
- "Notice how the `!`s tend to come in pairs, except near the sides.\n",
- "This \"comes in pairs\" property is extremely important, because it allows you to perform error correction.\n",
- "Every `!` must be paired with another `!`, with the left boundary, or with the right boundary.\n",
- "In the circuit generated by Stim, the logical observable is annotated to be a measurement of the leftmost data qubit.\n",
- "That data qubit was flipped once for each `!` that's paired with the left boundary.\n",
- "If the data qubit was flipped an even number of times, the observable that was measured is correct.\n",
- "If it was flipped an odd number of times, the observable that was measured needs to be flipped to be correct.\n",
- "If you just had a syndrome decoder, you could use it to solve the matching problem and figure out if the leftmost data qubit (and therefore the protected logical observable) ended up flipped or not...\n",
- "\n",
- "\n",
- "# 6. Use `pymatching` to correct errors in a circuit\n",
- "\n",
- "Stim has a key feature that makes it easier to use a decoder: converting a circuit into a detector error model.\n",
- "A detector error model is just a list of all the independent error mechanisms in a circuit, as well as their symptoms (which detectors they set off) and frame changes (which logical observables they flip).\n",
- "\n",
- "You can get the detector error mode for a circuit by calling [`circuit.detector_error_model()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.detector_error_model):"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "dem = circuit.detector_error_model()\nprint(repr(dem))",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -2015,135 +1651,30 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "stim.DetectorErrorModel('''\n",
- " error(0.0266667) D0\n",
- " error(0.0266667) D0 D1\n",
- " error(0.01) D0 D8\n",
- " error(0.0266667) D1 D2\n",
- " error(0.01) D1 D9\n",
- " error(0.0266667) D2 D3\n",
- " error(0.01) D2 D10\n",
- " error(0.0266667) D3 D4\n",
- " error(0.01) D3 D11\n",
- " error(0.0266667) D4 D5\n",
- " error(0.01) D4 D12\n",
- " error(0.0266667) D5 D6\n",
- " error(0.01) D5 D13\n",
- " error(0.0266667) D6 D7\n",
- " error(0.01) D6 D14\n",
- " error(0.01) D7 D15\n",
- " error(0.0266667) D7 L0\n",
- " detector(1, 0) D0\n",
- " detector(3, 0) D1\n",
- " detector(5, 0) D2\n",
- " detector(7, 0) D3\n",
- " detector(9, 0) D4\n",
- " detector(11, 0) D5\n",
- " detector(13, 0) D6\n",
- " detector(15, 0) D7\n",
- " repeat 23 {\n",
- " error(0.0266667) D8\n",
- " error(0.0266667) D8 D9\n",
- " error(0.01) D8 D16\n",
- " error(0.0266667) D9 D10\n",
- " error(0.01) D9 D17\n",
- " error(0.0266667) D10 D11\n",
- " error(0.01) D10 D18\n",
- " error(0.0266667) D11 D12\n",
- " error(0.01) D11 D19\n",
- " error(0.0266667) D12 D13\n",
- " error(0.01) D12 D20\n",
- " error(0.0266667) D13 D14\n",
- " error(0.01) D13 D21\n",
- " error(0.0266667) D14 D15\n",
- " error(0.01) D14 D22\n",
- " error(0.01) D15 D23\n",
- " error(0.0266667) D15 L0\n",
- " shift_detectors(0, 1) 0\n",
- " detector(1, 0) D8\n",
- " detector(3, 0) D9\n",
- " detector(5, 0) D10\n",
- " detector(7, 0) D11\n",
- " detector(9, 0) D12\n",
- " detector(11, 0) D13\n",
- " detector(13, 0) D14\n",
- " detector(15, 0) D15\n",
- " shift_detectors 8\n",
- " }\n",
- " error(0.0266667) D8\n",
- " error(0.0266667) D8 D9\n",
- " error(0.01) D8 D16\n",
- " error(0.0266667) D9 D10\n",
- " error(0.01) D9 D17\n",
- " error(0.0266667) D10 D11\n",
- " error(0.01) D10 D18\n",
- " error(0.0266667) D11 D12\n",
- " error(0.01) D11 D19\n",
- " error(0.0266667) D12 D13\n",
- " error(0.01) D12 D20\n",
- " error(0.0266667) D13 D14\n",
- " error(0.01) D13 D21\n",
- " error(0.0266667) D14 D15\n",
- " error(0.01) D14 D22\n",
- " error(0.01) D15 D23\n",
- " error(0.0266667) D15 L0\n",
- " error(0.01) D16\n",
- " error(0.01) D16 D17\n",
- " error(0.01) D17 D18\n",
- " error(0.01) D18 D19\n",
- " error(0.01) D19 D20\n",
- " error(0.01) D20 D21\n",
- " error(0.01) D21 D22\n",
- " error(0.01) D22 D23\n",
- " error(0.01) D23 L0\n",
- " shift_detectors(0, 1) 0\n",
- " detector(1, 0) D8\n",
- " detector(3, 0) D9\n",
- " detector(5, 0) D10\n",
- " detector(7, 0) D11\n",
- " detector(9, 0) D12\n",
- " detector(11, 0) D13\n",
- " detector(13, 0) D14\n",
- " detector(15, 0) D15\n",
- " detector(1, 1) D16\n",
- " detector(3, 1) D17\n",
- " detector(5, 1) D18\n",
- " detector(7, 1) D19\n",
- " detector(9, 1) D20\n",
- " detector(11, 1) D21\n",
- " detector(13, 1) D22\n",
- " detector(15, 1) D23\n",
- "''')\n"
- ]
+ "text": "stim.DetectorErrorModel('''\n, error(0.0266667) D0\n, error(0.0266667) D0 D1\n, error(0.01) D0 D8\n, error(0.0266667) D1 D2\n, error(0.01) D1 D9\n, error(0.0266667) D2 D3\n, error(0.01) D2 D10\n, error(0.0266667) D3 D4\n, error(0.01) D3 D11\n, error(0.0266667) D4 D5\n, error(0.01) D4 D12\n, error(0.0266667) D5 D6\n, error(0.01) D5 D13\n, error(0.0266667) D6 D7\n, error(0.01) D6 D14\n, error(0.01) D7 D15\n, error(0.0266667) D7 L0\n, detector(1, 0) D0\n, detector(3, 0) D1\n, detector(5, 0) D2\n, detector(7, 0) D3\n, detector(9, 0) D4\n, detector(11, 0) D5\n, detector(13, 0) D6\n, detector(15, 0) D7\n, repeat 23 {\n, error(0.0266667) D8\n, error(0.0266667) D8 D9\n, error(0.01) D8 D16\n, error(0.0266667) D9 D10\n, error(0.01) D9 D17\n, error(0.0266667) D10 D11\n, error(0.01) D10 D18\n, error(0.0266667) D11 D12\n, error(0.01) D11 D19\n, error(0.0266667) D12 D13\n, error(0.01) D12 D20\n, error(0.0266667) D13 D14\n, error(0.01) D13 D21\n, error(0.0266667) D14 D15\n, error(0.01) D14 D22\n, error(0.01) D15 D23\n, error(0.0266667) D15 L0\n, shift_detectors(0, 1) 0\n, detector(1, 0) D8\n, detector(3, 0) D9\n, detector(5, 0) D10\n, detector(7, 0) D11\n, detector(9, 0) D12\n, detector(11, 0) D13\n, detector(13, 0) D14\n, detector(15, 0) D15\n, shift_detectors 8\n, }\n, error(0.0266667) D8\n, error(0.0266667) D8 D9\n, error(0.01) D8 D16\n, error(0.0266667) D9 D10\n, error(0.01) D9 D17\n, error(0.0266667) D10 D11\n, error(0.01) D10 D18\n, error(0.0266667) D11 D12\n, error(0.01) D11 D19\n, error(0.0266667) D12 D13\n, error(0.01) D12 D20\n, error(0.0266667) D13 D14\n, error(0.01) D13 D21\n, error(0.0266667) D14 D15\n, error(0.01) D14 D22\n, error(0.01) D15 D23\n, error(0.0266667) D15 L0\n, error(0.01) D16\n, error(0.01) D16 D17\n, error(0.01) D17 D18\n, error(0.01) D18 D19\n, error(0.01) D19 D20\n, error(0.01) D20 D21\n, error(0.01) D21 D22\n, error(0.01) D22 D23\n, error(0.01) D23 L0\n, shift_detectors(0, 1) 0\n, detector(1, 0) D8\n, detector(3, 0) D9\n, detector(5, 0) D10\n, detector(7, 0) D11\n, detector(9, 0) D12\n, detector(11, 0) D13\n, detector(13, 0) D14\n, detector(15, 0) D15\n, detector(1, 1) D16\n, detector(3, 1) D17\n, detector(5, 1) D18\n, detector(7, 1) D19\n, detector(9, 1) D20\n, detector(11, 1) D21\n, detector(13, 1) D22\n, detector(15, 1) D23\n,''')\n"
}
],
- "source": [
- "dem = circuit.detector_error_model()\n",
- "print(repr(dem))"
- ]
+ "execution_count": null
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "",
"metadata": {
"id": "QgqQ90GlBcB_"
},
"outputs": [],
- "source": []
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can view the detector error model as a graph by using the `matchgraph-svg` diagram. Note that this diagram looking good relies heavily on the circuit specifying coordinate data for its detectors. Fortunately, the circuit you generated includes good coordinate data:",
"metadata": {
"id": "2NpcBtBM-qOS"
- },
- "source": [
- "You can view the detector error model as a graph by using the `matchgraph-svg` diagram. Note that this diagram looking good relies heavily on the circuit specifying coordinate data for its detectors. Fortunately, the circuit you generated includes good coordinate data:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "dem.diagram(\"matchgraph-svg\")",
"metadata": {
"id": "DrUUoFMu-qOV",
"outputId": "1ee89575-a83e-47ad-de32-f636edd8726d"
@@ -2585,112 +2116,59 @@
"output_type": "execute_result"
}
],
- "source": [
- "dem.diagram(\"matchgraph-svg\")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "In the diagram above, each node is a detector and each edge is an error mechanism. The matcher is going to decode errors by trying to match each excited node to another nearby excited node, or to the side boundaries, which minimizes the number of edges that were used.\n\nThe detector error model format is easier for decoders to consume than a raw circuit, because everything is explained in terms of observable symptoms and hidden symptoms, which is how decoders usually conceptualize the problem space.\nFor example, some decoders can be configured using a weighted graph, and [`stim.DetectorErrorModel`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.DetectorErrorModel) is effectively just a weighted graph.\nIt might be a pain to write the glue code that converts the [`stim.DetectorErrorModel`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.DetectorErrorModel) into exactly the right kind of graph expected by the decoder, but it's much easier than starting from the circuit or generating the graph from scratch – and you only have to write that code once instead of once per circuit.\n\nFor this tutorial, you'll use existing packages instead of writing your own glue code.\nSpecifically, you'll use the open-source package [PyMatching](https://github.com/oscarhiggott/PyMatching) as your decoder.\nPyMatching is a minimum-weight perfect matching decoder written by Oscar Higgott.\nYou can install it using `pip install pymatching`:",
"metadata": {
"id": "fLY3a5w9PT1L"
- },
- "source": [
- "In the diagram above, each node is a detector and each edge is an error mechanism. The matcher is going to decode errors by trying to match each excited node to another nearby excited node, or to the side boundaries, which minimizes the number of edges that were used.\n",
- "\n",
- "The detector error model format is easier for decoders to consume than a raw circuit, because everything is explained in terms of observable symptoms and hidden symptoms, which is how decoders usually conceptualize the problem space.\n",
- "For example, some decoders can be configured using a weighted graph, and [`stim.DetectorErrorModel`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.DetectorErrorModel) is effectively just a weighted graph.\n",
- "It might be a pain to write the glue code that converts the [`stim.DetectorErrorModel`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.DetectorErrorModel) into exactly the right kind of graph expected by the decoder, but it's much easier than starting from the circuit or generating the graph from scratch – and you only have to write that code once instead of once per circuit.\n",
- "\n",
- "For this tutorial, you'll use existing packages instead of writing your own glue code.\n",
- "Specifically, you'll use the open-source package [PyMatching](https://github.com/oscarhiggott/PyMatching) as your decoder.\n",
- "PyMatching is a minimum-weight perfect matching decoder written by Oscar Higgott.\n",
- "You can install it using `pip install pymatching`:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "!pip install pymatching~=2.0",
"metadata": {
"id": "xlH-hxBRPjNy"
},
"outputs": [],
- "source": [
- "!pip install pymatching~=2.0"
- ]
+ "execution_count": null
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "import pymatching",
"metadata": {
"id": "cx7UkBiYQeOz"
},
"outputs": [],
- "source": [
- "import pymatching"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Now you're going to write a method that will sample a circuit using Stim, decode it using PyMatching, and count how often it gets the right answer.\n\nFirst, you sample detection events and observable flips from the circuit.\nYou do this by creating a sampler with [`circuit.compile_detector_sampler()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_detector_sampler) and then calling [`sampler.sample(shots, separate_observables=True)`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.CompiledDetectorSampler.sample).\nThe `separate_observables=True` argument is saying that you want the result of the method to be a tuple where the first entry is detection event data to give to the decoder and the second entry is the observable flip data the decoder is supposed to predict.\n\nSecond, you extract decoder information by using [`stim.Circuit.detector_error_model(...)`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.detector_error_model) and create a decoder from this information using [`pymatching.Matching.from_detector_error_model`](https://pymatching.readthedocs.io/en/latest/api.html#pymatching.matching.Matching.from_detector_error_model).\n\nThird, you run `matching.predict` to get the predicted observable flips.\n\nFourth, you compare the predictions made by PyMatching to the actual observable flip data that was sampled.\nAnytime the prediction differs, it indicates a logical error.",
"metadata": {
"id": "ewrxiwXMQ-Yz"
- },
- "source": [
- "Now you're going to write a method that will sample a circuit using Stim, decode it using PyMatching, and count how often it gets the right answer.\n",
- "\n",
- "First, you sample detection events and observable flips from the circuit.\n",
- "You do this by creating a sampler with [`circuit.compile_detector_sampler()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_detector_sampler) and then calling [`sampler.sample(shots, separate_observables=True)`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.CompiledDetectorSampler.sample).\n",
- "The `separate_observables=True` argument is saying that you want the result of the method to be a tuple where the first entry is detection event data to give to the decoder and the second entry is the observable flip data the decoder is supposed to predict.\n",
- "\n",
- "Second, you extract decoder information by using [`stim.Circuit.detector_error_model(...)`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.detector_error_model) and create a decoder from this information using [`pymatching.Matching.from_detector_error_model`](https://pymatching.readthedocs.io/en/latest/api.html#pymatching.matching.Matching.from_detector_error_model).\n",
- "\n",
- "Third, you run `matching.predict` to get the predicted observable flips.\n",
- "\n",
- "Fourth, you compare the predictions made by PyMatching to the actual observable flip data that was sampled.\n",
- "Anytime the prediction differs, it indicates a logical error."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "def count_logical_errors(circuit: stim.Circuit, num_shots: int) -> int:\n # Sample the circuit.\n sampler = circuit.compile_detector_sampler()\n detection_events, observable_flips = sampler.sample(num_shots, separate_observables=True)\n\n # Configure a decoder using the circuit.\n detector_error_model = circuit.detector_error_model(decompose_errors=True)\n matcher = pymatching.Matching.from_detector_error_model(detector_error_model)\n\n # Run the decoder.\n predictions = matcher.decode_batch(detection_events)\n\n # Count the mistakes.\n num_errors = 0\n for shot in range(num_shots):\n actual_for_shot = observable_flips[shot]\n predicted_for_shot = predictions[shot]\n if not np.array_equal(actual_for_shot, predicted_for_shot):\n num_errors += 1\n return num_errors",
"metadata": {
"id": "32hBrUAQRbSc"
},
"outputs": [],
- "source": [
- "def count_logical_errors(circuit: stim.Circuit, num_shots: int) -> int:\n",
- " # Sample the circuit.\n",
- " sampler = circuit.compile_detector_sampler()\n",
- " detection_events, observable_flips = sampler.sample(num_shots, separate_observables=True)\n",
- "\n",
- " # Configure a decoder using the circuit.\n",
- " detector_error_model = circuit.detector_error_model(decompose_errors=True)\n",
- " matcher = pymatching.Matching.from_detector_error_model(detector_error_model)\n",
- "\n",
- " # Run the decoder.\n",
- " predictions = matcher.decode_batch(detection_events)\n",
- "\n",
- " # Count the mistakes.\n",
- " num_errors = 0\n",
- " for shot in range(num_shots):\n",
- " actual_for_shot = observable_flips[shot]\n",
- " predicted_for_shot = predictions[shot]\n",
- " if not np.array_equal(actual_for_shot, predicted_for_shot):\n",
- " num_errors += 1\n",
- " return num_errors"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can try this method on the repetition code circuit:",
"metadata": {
"id": "gVvL0sbLSi4R"
- },
- "source": [
- "You can try this method on the repetition code circuit:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit = stim.Circuit.generated(\"repetition_code:memory\", rounds=100, distance=9, before_round_data_depolarization=0.03)\nnum_shots = 100_000\nnum_logical_errors = count_logical_errors(circuit, num_shots)\nprint(\"there were\", num_logical_errors, \"wrong predictions (logical errors) out of\", num_shots, \"shots\")",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -2702,31 +2180,21 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "there were 5 wrong predictions (logical errors) out of 100000 shots\n"
- ]
+ "text": "there were 5 wrong predictions (logical errors) out of 100000 shots\n"
}
],
- "source": [
- "circuit = stim.Circuit.generated(\"repetition_code:memory\", rounds=100, distance=9, before_round_data_depolarization=0.03)\n",
- "num_shots = 100_000\n",
- "num_logical_errors = count_logical_errors(circuit, num_shots)\n",
- "print(\"there were\", num_logical_errors, \"wrong predictions (logical errors) out of\", num_shots, \"shots\")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can check that increasing the physical noise strength increases the logical error rate.\nTry increasing the between-round depolarization strength to 13%:",
"metadata": {
"id": "jRbSSRC2TcBA"
- },
- "source": [
- "You can check that increasing the physical noise strength increases the logical error rate.\n",
- "Try increasing the between-round depolarization strength to 13%:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "circuit = stim.Circuit.generated(\n \"repetition_code:memory\",\n rounds=100,\n distance=9,\n before_round_data_depolarization=0.13,\n before_measure_flip_probability=0.01)\nnum_shots = 10_000\nnum_logical_errors = count_logical_errors(circuit, num_shots)\nprint(\"there were\", num_logical_errors, \"wrong predictions (logical errors) out of\", num_shots, \"shots\")",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -2738,52 +2206,28 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "there were 1234 wrong predictions (logical errors) out of 10000 shots\n"
- ]
+ "text": "there were 1234 wrong predictions (logical errors) out of 10000 shots\n"
}
],
- "source": [
- "circuit = stim.Circuit.generated(\n",
- " \"repetition_code:memory\",\n",
- " rounds=100,\n",
- " distance=9,\n",
- " before_round_data_depolarization=0.13,\n",
- " before_measure_flip_probability=0.01)\n",
- "num_shots = 10_000\n",
- "num_logical_errors = count_logical_errors(circuit, num_shots)\n",
- "print(\"there were\", num_logical_errors, \"wrong predictions (logical errors) out of\", num_shots, \"shots\")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "As you can see, you get a lot more wrong predictions with this higher noise strength.",
"metadata": {
"id": "j2WD8EIIYSsO"
- },
- "source": [
- "As you can see, you get a lot more wrong predictions with this higher noise strength."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 7. Estimate the threshold of a repetition code using Monte Carlo sampling\n\nEstimating the threshold of an error correcting code really just comes down to trying a bunch of physical error rates and code distances.\nYou plot out the logical error rate vs physical error rate curve for each distance, and see where the curves cross.\nThat's where the physical error rate gets bad enough that increasing the distance starts to make the logical error rate worse, instead of better.\nThat's the threshold physical error rate.\n\nYou can estimate the threshold of the repetition code, for the specific type of noise you're using, by plotting the logical error rate at various code distances and physical error rates:",
"metadata": {
"id": "pJt8euOoT1kQ"
- },
- "source": [
- "\n",
- "# 7. Estimate the threshold of a repetition code using Monte Carlo sampling\n",
- "\n",
- "Estimating the threshold of an error correcting code really just comes down to trying a bunch of physical error rates and code distances.\n",
- "You plot out the logical error rate vs physical error rate curve for each distance, and see where the curves cross.\n",
- "That's where the physical error rate gets bad enough that increasing the distance starts to make the logical error rate worse, instead of better.\n",
- "That's the threshold physical error rate.\n",
- "\n",
- "You can estimate the threshold of the repetition code, for the specific type of noise you're using, by plotting the logical error rate at various code distances and physical error rates:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "import matplotlib.pyplot as plt\n\nnum_shots = 10_000\nfor d in [3, 5, 7]:\n xs = []\n ys = []\n for noise in [0.1, 0.2, 0.3, 0.4, 0.5]:\n circuit = stim.Circuit.generated(\n \"repetition_code:memory\",\n rounds=d * 3,\n distance=d,\n before_round_data_depolarization=noise)\n num_errors_sampled = count_logical_errors(circuit, num_shots)\n xs.append(noise)\n ys.append(num_errors_sampled / num_shots)\n plt.plot(xs, ys, label=\"d=\" + str(d))\nplt.loglog()\nplt.xlabel(\"physical error rate\")\nplt.ylabel(\"logical error rate per shot\")\nplt.legend()\nplt.show()",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -2804,132 +2248,66 @@
"output_type": "display_data"
}
],
- "source": [
- "import matplotlib.pyplot as plt\n",
- "\n",
- "num_shots = 10_000\n",
- "for d in [3, 5, 7]:\n",
- " xs = []\n",
- " ys = []\n",
- " for noise in [0.1, 0.2, 0.3, 0.4, 0.5]:\n",
- " circuit = stim.Circuit.generated(\n",
- " \"repetition_code:memory\",\n",
- " rounds=d * 3,\n",
- " distance=d,\n",
- " before_round_data_depolarization=noise)\n",
- " num_errors_sampled = count_logical_errors(circuit, num_shots)\n",
- " xs.append(noise)\n",
- " ys.append(num_errors_sampled / num_shots)\n",
- " plt.plot(xs, ys, label=\"d=\" + str(d))\n",
- "plt.loglog()\n",
- "plt.xlabel(\"physical error rate\")\n",
- "plt.ylabel(\"logical error rate per shot\")\n",
- "plt.legend()\n",
- "plt.show()"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "From the results here you can see that the repetition code has amazingly good performance! Well... it's not *quite* so amazing when you remember that you're using a phenomenological noise model (instead of a circuit-level noise model) and also that you're inserting depolarizing errors instead of bit-flip errors (the repetition code is immune to Z errors, and when a depolarizing error occurs it's a Z error one third of the time).\n\nStill, you can see that it's not so hard to run a few different cases and plot them out. A bit tedious, maybe.",
"metadata": {
"id": "J5TZ-AlJVGmk"
- },
- "source": [
- "From the results here you can see that the repetition code has amazingly good performance! Well... it's not *quite* so amazing when you remember that you're using a phenomenological noise model (instead of a circuit-level noise model) and also that you're inserting depolarizing errors instead of bit-flip errors (the repetition code is immune to Z errors, and when a depolarizing error occurs it's a Z error one third of the time).\n",
- "\n",
- "Still, you can see that it's not so hard to run a few different cases and plot them out. A bit tedious, maybe."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 8. Use `sinter` to streamline the Monte Carlo sampling process\n\nNow that you understand the basic workflow of sampling from a circuit, making a decoder predict the observable flips, and plotting out the result, you probably never want to do that by hand ever again. And that's without even getting into dividing work into batches, or across multiple CPU cores!\n\nFortunately, you can use [Sinter](https://pypi.org/project/sinter/) to do almost the entire thing for you. Install Sinter using `pip install sinter`:",
"metadata": {
"id": "c88KJx_mVhZU"
- },
- "source": [
- "\n",
- "# 8. Use `sinter` to streamline the Monte Carlo sampling process\n",
- "\n",
- "Now that you understand the basic workflow of sampling from a circuit, making a decoder predict the observable flips, and plotting out the result, you probably never want to do that by hand ever again. And that's without even getting into dividing work into batches, or across multiple CPU cores!\n",
- "\n",
- "Fortunately, you can use [Sinter](https://pypi.org/project/sinter/) to do almost the entire thing for you. Install Sinter using `pip install sinter`:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "!pip install sinter~=1.14",
"metadata": {
"id": "ogUrK7LhZyV-"
},
"outputs": [],
- "source": [
- "!pip install sinter~=1.14"
- ]
+ "execution_count": null
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "import sinter\nfrom typing import List",
"metadata": {
"id": "VrayGWt0-qOW"
},
"outputs": [],
- "source": [
- "import sinter\n",
- "from typing import List"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Wrap your circuits into [`sinter.Task`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.Task) instances, and give those tasks to [`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect).\nSinter will spin up multiple worker processes to sample from and decode these circuits.\n[`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect) takes a variety of useful options, such as the maximum number of shots or errors to take from each task, as well as the number of workers to use:",
"metadata": {
"id": "dxTADjNX-qOW"
- },
- "source": [
- "Wrap your circuits into [`sinter.Task`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.Task) instances, and give those tasks to [`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect).\n",
- "Sinter will spin up multiple worker processes to sample from and decode these circuits.\n",
- "[`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect) takes a variety of useful options, such as the maximum number of shots or errors to take from each task, as well as the number of workers to use:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "tasks = [\n sinter.Task(\n circuit=stim.Circuit.generated(\n \"repetition_code:memory\",\n rounds=d * 3,\n distance=d,\n before_round_data_depolarization=noise,\n ),\n json_metadata={'d': d, 'p': noise},\n )\n for d in [3, 5, 7, 9]\n for noise in [0.05, 0.08, 0.1, 0.2, 0.3, 0.4, 0.5]\n]\n\ncollected_stats: List[sinter.TaskStats] = sinter.collect(\n num_workers=4,\n tasks=tasks,\n decoders=['pymatching'],\n max_shots=100_000,\n max_errors=500,\n)",
"metadata": {
"id": "4HmwlVCz-qOW"
},
"outputs": [],
- "source": [
- "tasks = [\n",
- " sinter.Task(\n",
- " circuit=stim.Circuit.generated(\n",
- " \"repetition_code:memory\",\n",
- " rounds=d * 3,\n",
- " distance=d,\n",
- " before_round_data_depolarization=noise,\n",
- " ),\n",
- " json_metadata={'d': d, 'p': noise},\n",
- " )\n",
- " for d in [3, 5, 7, 9]\n",
- " for noise in [0.05, 0.08, 0.1, 0.2, 0.3, 0.4, 0.5]\n",
- "]\n",
- "\n",
- "collected_stats: List[sinter.TaskStats] = sinter.collect(\n",
- " num_workers=4,\n",
- " tasks=tasks,\n",
- " decoders=['pymatching'],\n",
- " max_shots=100_000,\n",
- " max_errors=500,\n",
- ")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Sinter also has a [`sinter.plot_error_rate`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.plot_error_rate) method which can be used to plot the logical error rates. This method automatically adds highlighted regions quantifying uncertainty in the estimates.",
"metadata": {
"id": "mVDInHcUbAc0"
- },
- "source": [
- "Sinter also has a [`sinter.plot_error_rate`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.plot_error_rate) method which can be used to plot the logical error rates. This method automatically adds highlighted regions quantifying uncertainty in the estimates."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "fig, ax = plt.subplots(1, 1)\nsinter.plot_error_rate(\n ax=ax,\n stats=collected_stats,\n x_func=lambda stats: stats.json_metadata['p'],\n group_func=lambda stats: stats.json_metadata['d'],\n)\nax.set_ylim(1e-4, 1e-0)\nax.set_xlim(5e-2, 5e-1)\nax.loglog()\nax.set_title(\"Repetition Code Error Rates (Phenomenological Noise)\")\nax.set_xlabel(\"Phyical Error Rate\")\nax.set_ylabel(\"Logical Error Rate per Shot\")\nax.grid(which='major')\nax.grid(which='minor')\nax.legend()\nfig.set_dpi(120) # Show it bigger",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -2950,85 +2328,41 @@
"output_type": "display_data"
}
],
- "source": [
- "fig, ax = plt.subplots(1, 1)\n",
- "sinter.plot_error_rate(\n",
- " ax=ax,\n",
- " stats=collected_stats,\n",
- " x_func=lambda stats: stats.json_metadata['p'],\n",
- " group_func=lambda stats: stats.json_metadata['d'],\n",
- ")\n",
- "ax.set_ylim(1e-4, 1e-0)\n",
- "ax.set_xlim(5e-2, 5e-1)\n",
- "ax.loglog()\n",
- "ax.set_title(\"Repetition Code Error Rates (Phenomenological Noise)\")\n",
- "ax.set_xlabel(\"Phyical Error Rate\")\n",
- "ax.set_ylabel(\"Logical Error Rate per Shot\")\n",
- "ax.grid(which='major')\n",
- "ax.grid(which='minor')\n",
- "ax.legend()\n",
- "fig.set_dpi(120) # Show it bigger"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "`sinter`'s goal is to make getting these kinds of results fast and easy.",
"metadata": {
"id": "gU4GZ66sZllH"
- },
- "source": [
- "`sinter`'s goal is to make getting these kinds of results fast and easy."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 9. Estimate the threshold and footprint of a surface code\n\nEstimating the threshold of a repetition code under phenomenelogical noise is one thing.\nEstimating the threshold of a true quantum code, such as a surface code, under circuit noise, is...\nwell, historically, it would be a whole other thing.\nBut when using Stim, and PyMatching, and Sinter, the workflow is exactly identical.\nThe only thing that changes are the circuits input into the process.\n\nThe hard part is making the circuits in the first place.\nSo, for this tutorial, you'll continue to lean on Stim's example circuits.\nYou can make simple surface code circuits using [`stim.Circuit.generated`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.generated).",
"metadata": {
"id": "fe0PdLck-qOW"
- },
- "source": [
- "\n",
- "# 9. Estimate the threshold and footprint of a surface code\n",
- "\n",
- "Estimating the threshold of a repetition code under phenomenelogical noise is one thing.\n",
- "Estimating the threshold of a true quantum code, such as a surface code, under circuit noise, is...\n",
- "well, historically, it would be a whole other thing.\n",
- "But when using Stim, and PyMatching, and Sinter, the workflow is exactly identical.\n",
- "The only thing that changes are the circuits input into the process.\n",
- "\n",
- "The hard part is making the circuits in the first place.\n",
- "So, for this tutorial, you'll continue to lean on Stim's example circuits.\n",
- "You can make simple surface code circuits using [`stim.Circuit.generated`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.generated)."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "surface_code_circuit = stim.Circuit.generated(\n \"surface_code:rotated_memory_z\",\n rounds=9,\n distance=3,\n after_clifford_depolarization=0.001,\n after_reset_flip_probability=0.001,\n before_measure_flip_probability=0.001,\n before_round_data_depolarization=0.001)",
"metadata": {
"id": "gAtDhdGuV--e"
},
"outputs": [],
- "source": [
- "surface_code_circuit = stim.Circuit.generated(\n",
- " \"surface_code:rotated_memory_z\",\n",
- " rounds=9,\n",
- " distance=3,\n",
- " after_clifford_depolarization=0.001,\n",
- " after_reset_flip_probability=0.001,\n",
- " before_measure_flip_probability=0.001,\n",
- " before_round_data_depolarization=0.001)"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Surface code circuits have a much more complex structure than repetition codes, because they are laid out in a 2-D grid instead of a 1-D line. A time slice diagram of the circuit without noise will be much clearer than a timeline diagram:",
"metadata": {
"id": "huyjsuMBfSP9"
- },
- "source": [
- "Surface code circuits have a much more complex structure than repetition codes, because they are laid out in a 2-D grid instead of a 1-D line. A time slice diagram of the circuit without noise will be much clearer than a timeline diagram:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "surface_code_circuit.without_noise().diagram(\"timeslice-svg\")",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -7902,22 +7236,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "surface_code_circuit.without_noise().diagram(\"timeslice-svg\")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can also make 3-D diagrams of the circuit, using `timeline-3d`.",
"metadata": {
"id": "fPOBAR4T-qOW"
- },
- "source": [
- "You can also make 3-D diagrams of the circuit, using `timeline-3d`."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "surface_code_circuit.without_noise().diagram(\"timeline-3d\")\n\n# Note: if you are viewing this notebook on GitHub, the 3d model viewer is likely blocked.\n# To view the 3d model, run this notebook locally or upload it to https://colab.google.com/\n# GLTF files can be viewed directly in online viewers such as https://gltf-viewer.donmccurdy.com/\n\n# The 3d viewer is interactive, try clicking and dragging!",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -8079,31 +7409,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "surface_code_circuit.without_noise().diagram(\"timeline-3d\")\n",
- "\n",
- "# Note: if you are viewing this notebook on GitHub, the 3d model viewer is likely blocked.\n",
- "# To view the 3d model, run this notebook locally or upload it to https://colab.google.com/\n",
- "# GLTF files can be viewed directly in online viewers such as https://gltf-viewer.donmccurdy.com/\n",
- "\n",
- "# The 3d viewer is interactive, try clicking and dragging!"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Yet another useful type of diagram, for understanding the structure of this circuit, is a \"detector slice diagram\".\nA detslice diagram shows how the stabilizers checked by the circuit's detectors change over time.\nIf you look carefully, you can see that, halfway through the measurement cycle of the surface code, its state is actually temporarily an even larger surface code!\nYou can also see the stabilizers establish themselves at the beginning of the circuit, and drain away at the end.",
"metadata": {
"id": "Hgh1I4Fefztj"
- },
- "source": [
- "Yet another useful type of diagram, for understanding the structure of this circuit, is a \"detector slice diagram\".\n",
- "A detslice diagram shows how the stabilizers checked by the circuit's detectors change over time.\n",
- "If you look carefully, you can see that, halfway through the measurement cycle of the surface code, its state is actually temporarily an even larger surface code!\n",
- "You can also see the stabilizers establish themselves at the beginning of the circuit, and drain away at the end."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "surface_code_circuit.diagram(\"detslice-svg\")",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -18707,22 +18024,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "surface_code_circuit.diagram(\"detslice-svg\")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "There is also the diagram type `detslice-with-ops-svg`, which overlays the time slice and detslice diagrams. For example, `detslice-with-ops-svg` shows how the first round gradually projects the system into the surface code state.",
"metadata": {
"id": "pWcO6j68-qOW"
- },
- "source": [
- "There is also the diagram type `detslice-with-ops-svg`, which overlays the time slice and detslice diagrams. For example, `detslice-with-ops-svg` shows how the first round gradually projects the system into the surface code state."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "surface_code_circuit.without_noise().diagram(\n \"detslice-with-ops-svg\",\n tick=range(0, 9),\n)",
"metadata": {
"id": "aRPHBfk--qOW",
"outputId": "759ce9ba-6f21-4618-ee24-f31e5607ba0c"
@@ -20452,28 +19765,18 @@
"output_type": "execute_result"
}
],
- "source": [
- "surface_code_circuit.without_noise().diagram(\n",
- " \"detslice-with-ops-svg\",\n",
- " tick=range(0, 9),\n",
- ")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Notice that when you created this surface code circuit, you specified a lot more error parameters.\nThese parameters are adding full circuit noise, instead of just phenomenological noise.\nBecause the noise is richer, and because this is a quantum code instead of a classical code, the decoding problem is much harder and threshold is going to be noticeably lower.\nLooking at the match graph, you can see `pymatching` has a much more complicated problem to solve than before!",
"metadata": {
"id": "K75kGz3IWYAW"
- },
- "source": [
- "Notice that when you created this surface code circuit, you specified a lot more error parameters.\n",
- "These parameters are adding full circuit noise, instead of just phenomenological noise.\n",
- "Because the noise is richer, and because this is a quantum code instead of a classical code, the decoding problem is much harder and threshold is going to be noticeably lower.\n",
- "Looking at the match graph, you can see `pymatching` has a much more complicated problem to solve than before!"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "surface_code_circuit.diagram(\"matchgraph-3d\")\n\n# Note: if you are viewing this notebook on GitHub, the 3d model viewer is likely blocked.\n# To view the 3d model, run this notebook locally or upload it to https://colab.google.com/\n# GLTF files can be viewed directly in online viewers such as https://gltf-viewer.donmccurdy.com/",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -20635,78 +19938,35 @@
"output_type": "execute_result"
}
],
- "source": [
- "surface_code_circuit.diagram(\"matchgraph-3d\")\n",
- "\n",
- "# Note: if you are viewing this notebook on GitHub, the 3d model viewer is likely blocked.\n",
- "# To view the 3d model, run this notebook locally or upload it to https://colab.google.com/\n",
- "# GLTF files can be viewed directly in online viewers such as https://gltf-viewer.donmccurdy.com/"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Okay, enough looking at the circuits, time to collect.\n\nCollecting data using [`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect) will take a bit longer this time.\nYou can specify `print_progress=True` to get progress updates while the collection runs.\nAnother useful argument (not used here) is `save_resume_filepath`, which allows you to cancel and restart collection without losing the work that was done.",
"metadata": {
"id": "_aw3w686hJCa"
- },
- "source": [
- "Okay, enough looking at the circuits, time to collect.\n",
- "\n",
- "Collecting data using [`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect) will take a bit longer this time.\n",
- "You can specify `print_progress=True` to get progress updates while the collection runs.\n",
- "Another useful argument (not used here) is `save_resume_filepath`, which allows you to cancel and restart collection without losing the work that was done."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "import os\n\nsurface_code_tasks = [\n sinter.Task(\n circuit = stim.Circuit.generated(\n \"surface_code:rotated_memory_z\",\n rounds=d * 3,\n distance=d,\n after_clifford_depolarization=noise,\n after_reset_flip_probability=noise,\n before_measure_flip_probability=noise,\n before_round_data_depolarization=noise,\n ),\n json_metadata={'d': d, 'r': d * 3, 'p': noise},\n )\n for d in [3, 5, 7]\n for noise in [0.008, 0.009, 0.01, 0.011, 0.012]\n]\n\ncollected_surface_code_stats: List[sinter.TaskStats] = sinter.collect(\n num_workers=os.cpu_count(),\n tasks=surface_code_tasks,\n decoders=['pymatching'],\n max_shots=1_000_000,\n max_errors=5_000,\n print_progress=True,\n)",
"metadata": {
"id": "p4hgivJmeG0G",
"scrolled": true
},
"outputs": [],
- "source": [
- "import os\n",
- "\n",
- "surface_code_tasks = [\n",
- " sinter.Task(\n",
- " circuit = stim.Circuit.generated(\n",
- " \"surface_code:rotated_memory_z\",\n",
- " rounds=d * 3,\n",
- " distance=d,\n",
- " after_clifford_depolarization=noise,\n",
- " after_reset_flip_probability=noise,\n",
- " before_measure_flip_probability=noise,\n",
- " before_round_data_depolarization=noise,\n",
- " ),\n",
- " json_metadata={'d': d, 'r': d * 3, 'p': noise},\n",
- " )\n",
- " for d in [3, 5, 7]\n",
- " for noise in [0.008, 0.009, 0.01, 0.011, 0.012]\n",
- "]\n",
- "\n",
- "collected_surface_code_stats: List[sinter.TaskStats] = sinter.collect(\n",
- " num_workers=os.cpu_count(),\n",
- " tasks=surface_code_tasks,\n",
- " decoders=['pymatching'],\n",
- " max_shots=1_000_000,\n",
- " max_errors=5_000,\n",
- " print_progress=True,\n",
- ")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can now plot the collected data.\nTry using the `failure_units_per_shot_func` argument to plot per round error rates instead of per shot error rates, by retrieving the `'r'` entry (short for rounds) that you put in the metadata:",
"metadata": {
"id": "w3JgGXrSe5r-"
- },
- "source": [
- "You can now plot the collected data.\n",
- "Try using the `failure_units_per_shot_func` argument to plot per round error rates instead of per shot error rates, by retrieving the `'r'` entry (short for rounds) that you put in the metadata:"
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "fig, ax = plt.subplots(1, 1)\nsinter.plot_error_rate(\n ax=ax,\n stats=collected_surface_code_stats,\n x_func=lambda stat: stat.json_metadata['p'],\n group_func=lambda stat: stat.json_metadata['d'],\n failure_units_per_shot_func=lambda stat: stat.json_metadata['r'],\n)\nax.set_ylim(5e-3, 5e-2)\nax.set_xlim(0.008, 0.012)\nax.loglog()\nax.set_title(\"Surface Code Error Rates per Round under Circuit Noise\")\nax.set_xlabel(\"Phyical Error Rate\")\nax.set_ylabel(\"Logical Error Rate per Round\")\nax.grid(which='major')\nax.grid(which='minor')\nax.legend()\nfig.set_dpi(120) # Show it bigger",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -20727,94 +19987,35 @@
"output_type": "display_data"
}
],
- "source": [
- "fig, ax = plt.subplots(1, 1)\n",
- "sinter.plot_error_rate(\n",
- " ax=ax,\n",
- " stats=collected_surface_code_stats,\n",
- " x_func=lambda stat: stat.json_metadata['p'],\n",
- " group_func=lambda stat: stat.json_metadata['d'],\n",
- " failure_units_per_shot_func=lambda stat: stat.json_metadata['r'],\n",
- ")\n",
- "ax.set_ylim(5e-3, 5e-2)\n",
- "ax.set_xlim(0.008, 0.012)\n",
- "ax.loglog()\n",
- "ax.set_title(\"Surface Code Error Rates per Round under Circuit Noise\")\n",
- "ax.set_xlabel(\"Phyical Error Rate\")\n",
- "ax.set_ylabel(\"Logical Error Rate per Round\")\n",
- "ax.grid(which='major')\n",
- "ax.grid(which='minor')\n",
- "ax.legend()\n",
- "fig.set_dpi(120) # Show it bigger"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "You can see from the plot that the threshold of the surface code is roughly 1%.\n\nThere is a problem here, though.\nThe problem is that the threshold isn't the only metric you care about.\nThe threshold tells you the absolute worse qubit quality that could possibly work, but it doesn't tell you how many of those qubits you would need to hit a target logical error rate.\nWhat you **really** want to estimate is the quality *and corresponding quantity* of qubits needed to do fault tolerant computation.\n\nSuppose, for the sake of example, that you have qubits with a physical error rate of 0.1% according to the noise model you are using.\nCollect logical error rates from a variety of code distances so you can predict the code distance needed to achieve a target logical error rate.",
"metadata": {
"id": "6bPcsxWhZebc"
- },
- "source": [
- "You can see from the plot that the threshold of the surface code is roughly 1%.\n",
- "\n",
- "There is a problem here, though.\n",
- "The problem is that the threshold isn't the only metric you care about.\n",
- "The threshold tells you the absolute worse qubit quality that could possibly work, but it doesn't tell you how many of those qubits you would need to hit a target logical error rate.\n",
- "What you **really** want to estimate is the quality *and corresponding quantity* of qubits needed to do fault tolerant computation.\n",
- "\n",
- "Suppose, for the sake of example, that you have qubits with a physical error rate of 0.1% according to the noise model you are using.\n",
- "Collect logical error rates from a variety of code distances so you can predict the code distance needed to achieve a target logical error rate."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "noise = 1e-3\n\nsurface_code_tasks = [\n sinter.Task(\n circuit = stim.Circuit.generated(\n \"surface_code:rotated_memory_z\",\n rounds=d * 3,\n distance=d,\n after_clifford_depolarization=noise,\n after_reset_flip_probability=noise,\n before_measure_flip_probability=noise,\n before_round_data_depolarization=noise,\n ),\n json_metadata={'d': d, 'r': d * 3, 'p': noise},\n )\n for d in [3, 5, 7, 9]\n]\n\ncollected_surface_code_stats: List[sinter.TaskStats] = sinter.collect(\n num_workers=os.cpu_count(),\n tasks=surface_code_tasks,\n decoders=['pymatching'],\n max_shots=5_000_000,\n max_errors=100,\n print_progress=True,\n)",
"metadata": {
"id": "OVjDeVXzkEO2",
"scrolled": true
},
"outputs": [],
- "source": [
- "noise = 1e-3\n",
- "\n",
- "surface_code_tasks = [\n",
- " sinter.Task(\n",
- " circuit = stim.Circuit.generated(\n",
- " \"surface_code:rotated_memory_z\",\n",
- " rounds=d * 3,\n",
- " distance=d,\n",
- " after_clifford_depolarization=noise,\n",
- " after_reset_flip_probability=noise,\n",
- " before_measure_flip_probability=noise,\n",
- " before_round_data_depolarization=noise,\n",
- " ),\n",
- " json_metadata={'d': d, 'r': d * 3, 'p': noise},\n",
- " )\n",
- " for d in [3, 5, 7, 9]\n",
- "]\n",
- "\n",
- "collected_surface_code_stats: List[sinter.TaskStats] = sinter.collect(\n",
- " num_workers=os.cpu_count(),\n",
- " tasks=surface_code_tasks,\n",
- " decoders=['pymatching'],\n",
- " max_shots=5_000_000,\n",
- " max_errors=100,\n",
- " print_progress=True,\n",
- ")"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "To a good first approximation, logical error rates decrease exponentially with code distance.\nUse [SciPy](https://scipy.org/)'s [linear regression facilities](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html) to get a line fit of code distance versus log error rate.",
"metadata": {
"id": "41iMwGAQqYz2"
- },
- "source": [
- "To a good first approximation, logical error rates decrease exponentially with code distance.\n",
- "Use [SciPy](https://scipy.org/)'s [linear regression facilities](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html) to get a line fit of code distance versus log error rate."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "import scipy.stats\n\n# Compute the line fit.\nxs = []\nys = []\nlog_ys = []\nfor stats in collected_surface_code_stats:\n d = stats.json_metadata['d']\n if not stats.errors:\n print(f\"Didn't see any errors for d={d}\")\n continue\n per_shot = stats.errors / stats.shots\n per_round = sinter.shot_error_rate_to_piece_error_rate(per_shot, pieces=stats.json_metadata['r'])\n xs.append(d)\n ys.append(per_round)\n log_ys.append(np.log(per_round))\nfit = scipy.stats.linregress(xs, log_ys)\nprint(fit)",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -20826,44 +20027,21 @@
{
"name": "stdout",
"output_type": "stream",
- "text": [
- "LinregressResult(slope=-1.1895861614770902, intercept=-4.615053480324744, rvalue=-0.998930299836957, pvalue=0.0010697001630429748, stderr=0.0389381734731575, intercept_stderr=0.24932596232733958)\n"
- ]
+ "text": "LinregressResult(slope=-1.1895861614770902, intercept=-4.615053480324744, rvalue=-0.998930299836957, pvalue=0.0010697001630429748, stderr=0.0389381734731575, intercept_stderr=0.24932596232733958)\n"
}
],
- "source": [
- "import scipy.stats\n",
- "\n",
- "# Compute the line fit.\n",
- "xs = []\n",
- "ys = []\n",
- "log_ys = []\n",
- "for stats in collected_surface_code_stats:\n",
- " d = stats.json_metadata['d']\n",
- " if not stats.errors:\n",
- " print(f\"Didn't see any errors for d={d}\")\n",
- " continue\n",
- " per_shot = stats.errors / stats.shots\n",
- " per_round = sinter.shot_error_rate_to_piece_error_rate(per_shot, pieces=stats.json_metadata['r'])\n",
- " xs.append(d)\n",
- " ys.append(per_round)\n",
- " log_ys.append(np.log(per_round))\n",
- "fit = scipy.stats.linregress(xs, log_ys)\n",
- "print(fit)"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Plot the collected points and the line fit, to get a projection of the distance needed to achieve a per-round error rate below one in a trillion.",
"metadata": {
"id": "bt6fVetwq0os"
- },
- "source": [
- "Plot the collected points and the line fit, to get a projection of the distance needed to achieve a per-round error rate below one in a trillion."
- ]
+ }
},
{
"cell_type": "code",
- "execution_count": null,
+ "source": "fig, ax = plt.subplots(1, 1)\nax.scatter(xs, ys, label=f\"sampled logical error rate at p={noise}\")\nax.plot([0, 25],\n [np.exp(fit.intercept), np.exp(fit.intercept + fit.slope * 25)],\n linestyle='--',\n label='least squares line fit')\nax.set_ylim(1e-12, 1e-0)\nax.set_xlim(0, 25)\nax.semilogy()\nax.set_title(\"Projecting distance needed to survive a trillion rounds\")\nax.set_xlabel(\"Code Distance\")\nax.set_ylabel(\"Logical Error Rate per Round\")\nax.grid(which='major')\nax.grid(which='minor')\nax.legend()\nfig.set_dpi(120) # Show it bigger",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -20884,128 +20062,21 @@
"output_type": "display_data"
}
],
- "source": [
- "fig, ax = plt.subplots(1, 1)\n",
- "ax.scatter(xs, ys, label=f\"sampled logical error rate at p={noise}\")\n",
- "ax.plot([0, 25],\n",
- " [np.exp(fit.intercept), np.exp(fit.intercept + fit.slope * 25)],\n",
- " linestyle='--',\n",
- " label='least squares line fit')\n",
- "ax.set_ylim(1e-12, 1e-0)\n",
- "ax.set_xlim(0, 25)\n",
- "ax.semilogy()\n",
- "ax.set_title(\"Projecting distance needed to survive a trillion rounds\")\n",
- "ax.set_xlabel(\"Code Distance\")\n",
- "ax.set_ylabel(\"Logical Error Rate per Round\")\n",
- "ax.grid(which='major')\n",
- "ax.grid(which='minor')\n",
- "ax.legend()\n",
- "fig.set_dpi(120) # Show it bigger"
- ]
+ "execution_count": null
},
{
"cell_type": "markdown",
+ "source": "Based on this data, it looks like a distance 20 patch would be sufficient to survive a trillion rounds.\nThat's a surface code with around 800 physical qubits.\n\nBeware that this line fit is being extrapolated quite far. It would be wise to sample a few more code distances. Also, keep in mind that the footprint you just estimated is for a **specific realization of the surface code circuit**, using a **specific choice of circuit-level noise**, and using **a specific kind of decoder**. Also, you only estimated the error of memory in one basis (Z); to be thorough you have to also check the X basis.",
"metadata": {
"id": "F7fFfO-akgqF"
- },
- "source": [
- "Based on this data, it looks like a distance 20 patch would be sufficient to survive a trillion rounds.\n",
- "That's a surface code with around 800 physical qubits.\n",
- "\n",
- "Beware that this line fit is being extrapolated quite far. It would be wise to sample a few more code distances. Also, keep in mind that the footprint you just estimated is for a **specific realization of the surface code circuit**, using a **specific choice of circuit-level noise**, and using **a specific kind of decoder**. Also, you only estimated the error of memory in one basis (Z); to be thorough you have to also check the X basis."
- ]
+ }
},
{
"cell_type": "markdown",
+ "source": "\n# 11. Conclusion\n\nCongratulations for making it this far! Historically, estimating the threshold of a quantum error-correcting code under circuit noise would have taken weeks or months of work.\nBy leveraging open-source tools, you just did it in a single sitting.\nNicely done!\n\n\n# 12. Additional resources\n\n## Getting help\n\n- You can ask questions about quantum circuits, Stim, error correction, and related topics on the [Quantum Computing Stack Exchange](https://quantumcomputing.stackexchange.com/).\nUse the tag `stim`.\n\n## Stim reference material\n\n- [Stim Python API Reference](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md)\n- [Stim Supported Gates Reference](https://github.com/quantumlib/Stim/blob/main/doc/gates.md)\n- [Stim Command Line Reference](https://github.com/quantumlib/Stim/blob/main/doc/usage_command_line.md)\n- [Stim Circuit File Format (.stim)](https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md)\n- [Stim Detector Error model Format (.dem)](https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md)\n- [Stim Results Format Reference](https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md)\n\n## Talks and videos\n\n- [\"Software and the Honeycomb Code\"](https://www.youtube.com/watch?v=O3NaTGmY0Rw) by Craig Gidney at the weekly Duke/Pratt quantum computing seminar\n- [\"Estimating overheads for quantum fault-tolerance in the honeycomb code\"](https://www.youtube.com/watch?v=ND9OoqJ0NMw) by Mike Newman at the [APS March Meeting 2022](https://web.archive.org/web/20240716155117/https://meetings.aps.org/Meeting/MAR22/Content/4178)\n- [\"(Demo/Tutorial) Estimating the threshold of a new quantum code using Stim and PyMatching\"](https://www.youtube.com/watch?v=E9yj0o1LGII) by Craig Gidney\n- [\"Relaxing Hardware Requirements for Surface Code Circuits using Time Dynamics\"](https://www.youtube.com/watch?v=FuP1exdZJkg) by Matt McEwen at [QEC 2023](https://web.archive.org/web/20241013042627/https://quantum.sydney.edu.au/qec23)\n\n## Papers with Stim circuits\n\n- A list of papers known to have included downloadable Stim circuits is available from the [doc/circuit_data_references.md](circuit_data_references.md) file in the [Stim repository on GitHub](https://github.com/quantumlib/stim).\n\n## Learning Python\n\n- [Google's Python class](https://developers.google.com/edu/python)\n- [Google's Crash Course on Python](https://www.coursera.org/learn/python-crash-course) at Coursera\n- University of Michigan's [Python for Everybody](https://www.coursera.org/specializations/python) at Coursera\n- Python.org's [Python Tutorial](https://docs.python.org/3/tutorial/)\n\n## Learning quantum computing\n\n\n- [Quantum computing for the very curious](https://quantum.country/qcvc) by Andy Matuschak and Michael Nielsen\n- [Building Google's quantum computer](https://www.youtube.com/watch?v=dUdqfqS9Dvg) by Marissa Giustina (2018)\n- MIT's [Quantum Information Science I](https://openlearninglibrary.mit.edu/courses/course-v1:MITx+8.370.1x+1T2018/about)\n- John Preskill's [Ph/CS 219A Quantum Computation](https://www.youtube.com/playlist?list=PL0ojjrEqIyPy-1RRD8cTD_lF1hflo89Iu) on YouTube\n- Quantum AI's YouTube content:\n - [Quantum Programming with Cirq](https://www.youtube.com/playlist?list=PLpO2pyKisOjLVt_tDJ2K6ZTapZtHXPLB4)\n - [QuantumCasts](https://www.youtube.com/playlist?list=PLQY2H8rRoyvwcpm6Nf-fL4sIYQUXtq3HR)\n- [Quantum computing for the determined](https://michaelnielsen.org/blog/quantum-computing-for-the-determined/) by Michael Nielsen\n- Michael Nielsen and Isaac Chuang's [Quantum Computation And Quantum Information](https://archive.org/embed/QuantumComputationAndQuantumInformation10thAnniversaryEdition)\n\n\n## Learning quantum error correction\n\n- Quantum AI's [quantum computing journey](https://quantumai.google/learn/map)\n- Coursera course [Hands-on quantum error correction with Google Quantum AI](https://www.coursera.org/learn/quantum-error-correction) by Austin Fowler",
"metadata": {
"id": "lYPJMxqyEQvy"
- },
- "source": [
- "\n",
- "# 11. Conclusion\n",
- "\n",
- "Congratulations for making it this far! Historically, estimating the threshold of a quantum error-correcting code under circuit noise would have taken weeks or months of work.\n",
- "By leveraging open-source tools, you just did it in a single sitting.\n",
- "Nicely done!\n",
- "\n",
- "\n",
- "# 12. Additional resources\n",
- "\n",
- "## Getting help\n",
- "\n",
- "- You can ask questions about quantum circuits, Stim, error correction, and related topics on the [Quantum Computing Stack Exchange](https://quantumcomputing.stackexchange.com/).\n",
- "Use the tag `stim`.\n",
- "\n",
- "## Stim reference material\n",
- "\n",
- "- [Stim Python API Reference](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md)\n",
- "- [Stim Supported Gates Reference](https://github.com/quantumlib/Stim/blob/main/doc/gates.md)\n",
- "- [Stim Command Line Reference](https://github.com/quantumlib/Stim/blob/main/doc/usage_command_line.md)\n",
- "- [Stim Circuit File Format (.stim)](https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md)\n",
- "- [Stim Detector Error model Format (.dem)](https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md)\n",
- "- [Stim Results Format Reference](https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md)\n",
- "\n",
- "## Talks and videos\n",
- "\n",
- "- [\"Software and the Honeycomb Code\"](https://www.youtube.com/watch?v=O3NaTGmY0Rw) by Craig Gidney at the weekly Duke/Pratt quantum computing seminar\n",
- "- [\"Estimating overheads for quantum fault-tolerance in the honeycomb code\"](https://www.youtube.com/watch?v=ND9OoqJ0NMw) by Mike Newman at the [APS March Meeting 2022](https://web.archive.org/web/20240716155117/https://meetings.aps.org/Meeting/MAR22/Content/4178)\n",
- "- [\"(Demo/Tutorial) Estimating the threshold of a new quantum code using Stim and PyMatching\"](https://www.youtube.com/watch?v=E9yj0o1LGII) by Craig Gidney\n",
- "- [\"Relaxing Hardware Requirements for Surface Code Circuits using Time Dynamics\"](https://www.youtube.com/watch?v=FuP1exdZJkg) by Matt McEwen at [QEC 2023](https://web.archive.org/web/20241013042627/https://quantum.sydney.edu.au/qec23)\n",
- "\n",
- "## Papers with Stim circuits\n",
- "\n",
- "- A list of papers known to have included downloadable Stim circuits is available from the [doc/circuit_data_references.md](circuit_data_references.md) file in the [Stim repository on GitHub](https://github.com/quantumlib/stim).\n",
- "\n",
- "## Learning Python\n",
- "\n",
- "- [Google's Python class](https://developers.google.com/edu/python)\n",
- "- [Google's Crash Course on Python](https://www.coursera.org/learn/python-crash-course) at Coursera\n",
- "- University of Michigan's [Python for Everybody](https://www.coursera.org/specializations/python) at Coursera\n",
- "- Python.org's [Python Tutorial](https://docs.python.org/3/tutorial/)\n",
- "\n",
- "## Learning quantum computing\n",
- "\n",
- "\n",
- "- [Quantum computing for the very curious](https://quantum.country/qcvc) by Andy Matuschak and Michael Nielsen\n",
- "- [Building Google's quantum computer](https://www.youtube.com/watch?v=dUdqfqS9Dvg) by Marissa Giustina (2018)\n",
- "- MIT's [Quantum Information Science I](https://openlearninglibrary.mit.edu/courses/course-v1:MITx+8.370.1x+1T2018/about)\n",
- "- John Preskill's [Ph/CS 219A Quantum Computation](https://www.youtube.com/playlist?list=PL0ojjrEqIyPy-1RRD8cTD_lF1hflo89Iu) on YouTube\n",
- "- Quantum AI's YouTube content:\n",
- " - [Quantum Programming with Cirq](https://www.youtube.com/playlist?list=PLpO2pyKisOjLVt_tDJ2K6ZTapZtHXPLB4)\n",
- " - [QuantumCasts](https://www.youtube.com/playlist?list=PLQY2H8rRoyvwcpm6Nf-fL4sIYQUXtq3HR)\n",
- "- [Quantum computing for the determined](https://michaelnielsen.org/blog/quantum-computing-for-the-determined/) by Michael Nielsen\n",
- "- Michael Nielsen and Isaac Chuang's [Quantum Computation And Quantum Information](https://archive.org/embed/QuantumComputationAndQuantumInformation10thAnniversaryEdition)\n",
- "\n",
- "\n",
- "## Learning quantum error correction\n",
- "\n",
- "- Quantum AI's [quantum computing journey](https://quantumai.google/learn/map)\n",
- "- Coursera course [Hands-on quantum error correction with Google Quantum AI](https://www.coursera.org/learn/quantum-error-correction) by Austin Fowler"
- ]
+ }
}
- ],
- "metadata": {
- "colab": {
- "provenance": []
- },
- "kernelspec": {
- "display_name": "Python 3 (ipykernel)",
- "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.0"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
+ ]
+}
\ No newline at end of file