{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Memory\n",
"\n",
"This notebook demonstrates the simplest(trivial) form of computation: logical memory. More specifically, a logical qubit with distance $d$ remains idle for $d$ error correction cycles."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Construction\n",
"\n",
"A memory experiment can be represented with a single cube. The color of the cube determines the spatial/temporal boundary types.\n",
"\n",
"`tqec` provides builtin functions `tqec.gallery.memory` to construct it."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from tqec import Basis\n",
"from tqec.gallery import memory\n",
"\n",
"graph = memory(Basis.Z)\n",
"graph.view_as_html()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Memory experiment preserves the logical observable through time:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"correlation_surfaces = graph.find_correlation_surfaces()\n",
"graph.view_as_html(\n",
" pop_faces_at_direction=\"-Y\",\n",
" show_correlation_surface=correlation_surfaces[0],\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Circuit\n",
"\n",
"You can download the circuit for a $d=3$ logical Z memory experiment from [here](../media/gallery/memory/circuit.stim), or generate it with the code below. You can also open the circuit in [Crumble](https://algassert.com/crumble#circuit=Q(0,4)0;Q(1,1)1;Q(1,3)2;Q(1,5)3;Q(2,0)4;Q(2,2)5;Q(2,4)6;Q(3,1)7;Q(3,3)8;Q(3,5)9;Q(4,2)10;Q(4,4)11;Q(4,6)12;Q(5,1)13;Q(5,3)14;Q(5,5)15;Q(6,2)16;R_1_2_3_7_8_9_13_14_15;RX_0_4_5_6_10_11_12_16;POLYGON(0,0,1,0.25)1_7_8_2;POLYGON(0,0,1,0.25)13_14;POLYGON(0,0,1,0.25)2_3;POLYGON(0,0,1,0.25)8_14_15_9;POLYGON(1,0,0,0.25)7_1;POLYGON(1,0,0,0.25)7_13_14_8;POLYGON(1,0,0,0.25)2_8_9_3;POLYGON(1,0,0,0.25)15_9;TICK;CX_6_2_10_7_12_9;CZ_5_1_11_8_16_13;TICK;CX_6_8_10_13_12_15;CZ_0_2;TICK;CX_4_1_6_3_10_8;CZ_5_2_11_9_16_14;TICK;CZ_5_7_11_14;TICK;CX_4_7_6_9_10_14;CZ_0_3_5_8_11_15;TICK;MX_0_4_5_6_10_11_12_16;DT(0,4,0)rec[-8];DT(2,2,0)rec[-6];DT(4,4,0)rec[-3];DT(6,2,0)rec[-1];TICK;RX_0_4_5_6_10_11_12_16;TICK;CX_6_2_10_7_12_9;CZ_5_1_11_8_16_13;TICK;CX_6_8_10_13_12_15;CZ_0_2;TICK;CX_4_1_6_3_10_8;CZ_5_2_11_9_16_14;TICK;CZ_5_7_11_14;TICK;CX_4_7_6_9_10_14;CZ_0_3_5_8_11_15;TICK;MX_0_4_5_6_10_11_12_16;DT(0,4,1)rec[-8]_rec[-16];DT(2,0,1)rec[-7]_rec[-15];DT(2,2,1)rec[-6]_rec[-14];DT(2,4,1)rec[-5]_rec[-13];DT(4,2,1)rec[-4]_rec[-12];DT(4,4,1)rec[-3]_rec[-11];DT(4,6,1)rec[-2]_rec[-10];DT(6,2,1)rec[-1]_rec[-9];TICK;RX_0_4_5_6_10_11_12_16;TICK;CX_6_2_10_7_12_9;CZ_5_1_11_8_16_13;TICK;CX_6_8_10_13_12_15;CZ_0_2;TICK;CX_4_1_6_3_10_8;CZ_5_2_11_9_16_14;TICK;CZ_5_7_11_14;TICK;CX_4_7_6_9_10_14;CZ_0_3_5_8_11_15;TICK;M_1_2_3_7_8_9_13_14_15;MX_0_4_5_6_10_11_12_16;DT(1,3,2)rec[-8]_rec[-15]_rec[-16];DT(0,4,2)rec[-8]_rec[-25];DT(2,0,2)rec[-7]_rec[-24];DT(2,2,2)rec[-6]_rec[-13]_rec[-14]_rec[-16]_rec[-17];DT(2,2,3)rec[-6]_rec[-23];DT(2,4,2)rec[-5]_rec[-22];DT(4,2,2)rec[-4]_rec[-21];DT(4,4,2)rec[-3]_rec[-9]_rec[-10]_rec[-12]_rec[-13];DT(4,4,3)rec[-3]_rec[-20];DT(4,6,2)rec[-2]_rec[-19];DT(5,3,2)rec[-1]_rec[-10]_rec[-11];DT(6,2,2)rec[-1]_rec[-18];OI(0)rec[-10]_rec[-13]_rec[-16]).\n",
"\n",
".. note::\n",
" Note that the syndrome extraction circuits used here are of depth-7 because we use an extra layer of two-qubit gates to align with the potential spatial cubes. The depth can be reduced to 6 with some post-processing on the circuit."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"from tqec import compile_block_graph, NoiseModel\n",
"\n",
"compiled_graph = compile_block_graph(graph)\n",
"circuit = compiled_graph.generate_stim_circuit(\n",
" k=1, noise_model=NoiseModel.uniform_depolarizing(p=0.001)\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we show the simulation results of both Z-basis and X-basis memory experiments under **uniform depolarizing** noise mode.\n",
"\n",
"Click to show the full code used for simulation
\n",
"\n",
"```py\n",
"from pathlib import Path\n",
"\n",
"import matplotlib.pyplot as plt\n",
"import numpy\n",
"import sinter\n",
"\n",
"from tqec.gallery.memory import memory\n",
"from tqec import NoiseModel\n",
"from tqec.simulation.plotting.inset import plot_observable_as_inset\n",
"from tqec.simulation.simulation import start_simulation_using_sinter\n",
"from tqec.utils.enums import Basis\n",
"\n",
"SAVE_DIR = Path(\"results\")\n",
"\n",
"\n",
"def generate_graphs(support_observable_basis: Basis) -> None:\n",
" block_graph = memory(support_observable_basis)\n",
" zx_graph = block_graph.to_zx_graph()\n",
"\n",
" correlation_surfaces = block_graph.find_correlation_surfaces()\n",
"\n",
" stats = start_simulation_using_sinter(\n",
" block_graph,\n",
" range(1, 4),\n",
" list(numpy.logspace(-4, -1, 10)),\n",
" NoiseModel.uniform_depolarizing,\n",
" manhattan_radius=2,\n",
" observables=correlation_surfaces,\n",
" num_workers=20,\n",
" max_shots=10_000_000,\n",
" max_errors=5_000,\n",
" decoders=[\"pymatching\"],\n",
" print_progress=True,\n",
" )\n",
"\n",
" for i, stat in enumerate(stats):\n",
" fig, ax = plt.subplots()\n",
" sinter.plot_error_rate(\n",
" ax=ax,\n",
" stats=stat,\n",
" x_func=lambda stat: stat.json_metadata[\"p\"],\n",
" failure_units_per_shot_func=lambda stat: stat.json_metadata[\"d\"],\n",
" group_func=lambda stat: stat.json_metadata[\"d\"],\n",
" )\n",
" plot_observable_as_inset(ax, zx_graph, correlation_surfaces[i])\n",
" ax.grid(axis=\"both\")\n",
" ax.legend()\n",
" ax.loglog()\n",
" ax.set_title(\"Logical Memory Error Rate\")\n",
" ax.set_xlabel(\"Physical Error Rate\")\n",
" ax.set_ylabel(\"Logical Error Rate(per round)\")\n",
" fig.savefig(\n",
" SAVE_DIR\n",
" / f\"logical_memory_result_{support_observable_basis}_observable_{i}.png\"\n",
" )\n",
"\n",
"\n",
"def main():\n",
" SAVE_DIR.mkdir(exist_ok=True)\n",
" generate_graphs(Basis.Z)\n",
" generate_graphs(Basis.X)\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()\n",
"\n",
"```\n",
"\n",
" \n",
"\n",
"\n",
"\n",
"#### X-basis\n",
"\n",
"\n",
"\n",
"#### Z-basis\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## References\n",
"\n",
"- Acharya, Rajeev, et al. \"Quantum error correction below the surface code threshold.\" arXiv preprint arXiv:2408.13687 (2024)."
]
}
],
"metadata": {
"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.12.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}