qiskit-documentation/docs/tutorials/repetition-codes.ipynb

524 lines
16 KiB
Plaintext

{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "f5d21946",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"# Repetition codes\n",
"*Estimated QPU usage: 4 seconds (tested on IBM Sherbrooke)*\n",
"\n",
"## Background\n",
"\n",
"To enable real-time quantum error correction (QEC), you need to be able to dynamically control quantum program flow during execution so that quantum gates can be conditioned on measurement results. This tutorial runs the bit-flip code, which is a very simple form of QEC. It demonstrates a dynamic quantum circuit that can protect an encoded qubit from a single bit-flip error, and then evaluates the bit-flip code performance.\n",
"\n",
"You can exploit additional ancilla qubits and entanglement to measure *stabilizers* that do not transform encoded quantum information, while still informing you of some classes of errors that might have occurred. A quantum stabilizer code encodes $k$ logical qubits into $n$ physical qubits. Stabilizer codes critically focus on correcting a discrete error set with support from the Pauli group $\\Pi^n$.\n",
"\n",
"For more information about QEC, refer to [Quantum Error Correction for Beginners.](https://arxiv.org/abs/0905.2794)"
]
},
{
"cell_type": "markdown",
"id": "88672bd6",
"metadata": {},
"source": [
"## Requirements\n",
"\n",
"Before starting this tutorial, ensure that you have the following installed:\n",
"\n",
"- Qiskit SDK 1.0 or later with visualization support (`pip install qiskit[visualization]`)\n",
"- Qiskit Runtime 0.22 or later (`pip install qiskit-ibm-runtime`)"
]
},
{
"cell_type": "markdown",
"id": "14c29e8b",
"metadata": {},
"source": [
"## Setup"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "1b9fd8ad",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"# Qiskit imports\n",
"from qiskit import (\n",
" QuantumCircuit,\n",
" QuantumRegister,\n",
" ClassicalRegister,\n",
")\n",
"\n",
"# Qiskit Runtime\n",
"from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler\n",
"\n",
"service = QiskitRuntimeService()"
]
},
{
"cell_type": "markdown",
"id": "4d01e8d3",
"metadata": {},
"source": [
"## Step 1. Map classical inputs to a quantum problem"
]
},
{
"cell_type": "markdown",
"id": "cdee0b18",
"metadata": {},
"source": [
"### Build a bit-flip stabilizer circuit\n",
"\n",
"The bit-flip code is among the simplest examples of a stabilizer code. It protects the state against a single bit-flip (X) error on any of the encoding qubits. Consider the action of bit-flip error $X$, which maps $|0\\rangle \\rightarrow |1\\rangle$ and $|1\\rangle \\rightarrow |0\\rangle$ on any of our qubits, then we have $\\epsilon = \\{E_0, E_1, E_2 \\} = \\{IIX, IXI, XII\\}$. The code requires five qubits: three are used to encode the protected state, and the remaining two are used as stabilizer measurement ancillas."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "b588703a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<IBMBackend('test_eagle_us-east')>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"num_qubits = 5\n",
"backend = service.least_busy(\n",
" operational=True, simulator=False, min_num_qubits=num_qubits\n",
")\n",
"backend"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "606dff18",
"metadata": {},
"outputs": [],
"source": [
"qreg_data = QuantumRegister(3)\n",
"qreg_measure = QuantumRegister(2)\n",
"creg_data = ClassicalRegister(3, name=\"data\")\n",
"creg_syndrome = ClassicalRegister(2, name=\"syndrome\")\n",
"state_data = qreg_data[0]\n",
"ancillas_data = qreg_data[1:]\n",
"\n",
"\n",
"def build_qc():\n",
" \"\"\"Build a typical error correction circuit\"\"\"\n",
" return QuantumCircuit(qreg_data, qreg_measure, creg_data, creg_syndrome)\n",
"\n",
"\n",
"def initialize_qubits(circuit: QuantumCircuit):\n",
" \"\"\"Initialize qubit to |1>\"\"\"\n",
" circuit.x(qreg_data[0])\n",
" circuit.barrier(qreg_data)\n",
" return circuit\n",
"\n",
"\n",
"def encode_bit_flip(circuit, state, ancillas) -> QuantumCircuit:\n",
" \"\"\"Encode bit-flip. This is done by simply adding a cx\"\"\"\n",
" for ancilla in ancillas:\n",
" circuit.cx(state, ancilla)\n",
" circuit.barrier(state, *ancillas)\n",
" return circuit\n",
"\n",
"\n",
"def measure_syndrome_bit(circuit, qreg_data, qreg_measure, creg_measure):\n",
" \"\"\"\n",
" Measure the syndrome by measuring the parity.\n",
" We reset our ancilla qubits after measuring the stabilizer\n",
" so we can reuse them for repeated stabilizer measurements.\n",
" Because we have already observed the state of the qubit,\n",
" we can write the conditional reset protocol directly to\n",
" avoid another round of qubit measurement if we used\n",
" the `reset` instruction.\n",
" \"\"\"\n",
" circuit.cx(qreg_data[0], qreg_measure[0])\n",
" circuit.cx(qreg_data[1], qreg_measure[0])\n",
" circuit.cx(qreg_data[0], qreg_measure[1])\n",
" circuit.cx(qreg_data[2], qreg_measure[1])\n",
" circuit.barrier(*qreg_data, *qreg_measure)\n",
" circuit.measure(qreg_measure, creg_measure)\n",
" with circuit.if_test((creg_syndrome[0], 1)):\n",
" circuit.x(qreg_measure[0])\n",
" with circuit.if_test((creg_syndrome[1], 1)):\n",
" circuit.x(qreg_measure[1])\n",
" circuit.barrier(*qreg_data, *qreg_measure)\n",
" return circuit\n",
"\n",
"\n",
"def apply_correction_bit(circuit, qreg_data, creg_syndrome):\n",
" \"\"\"We can detect where an error occurred and correct our state\"\"\"\n",
" with circuit.if_test((creg_syndrome, 3)):\n",
" circuit.x(qreg_data[0])\n",
" with circuit.if_test((creg_syndrome, 1)):\n",
" circuit.x(qreg_data[1])\n",
" with circuit.if_test((creg_syndrome, 2)):\n",
" circuit.x(qreg_data[2])\n",
" circuit.barrier(qreg_data)\n",
" return circuit\n",
"\n",
"\n",
"def apply_final_readout(circuit, qreg_data, creg_data):\n",
" \"\"\"Read out the final measurements\"\"\"\n",
" circuit.barrier(qreg_data)\n",
" circuit.measure(qreg_data, creg_data)\n",
" return circuit"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "dbe02949",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Image src=\"/docs/images/tutorials/repetition-codes/extracted-outputs/dbe02949-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def build_error_correction_sequence(apply_correction: bool) -> QuantumCircuit:\n",
" circuit = build_qc()\n",
" circuit = initialize_qubits(circuit)\n",
" circuit = encode_bit_flip(circuit, state_data, ancillas_data)\n",
" circuit = measure_syndrome_bit(\n",
" circuit, qreg_data, qreg_measure, creg_syndrome\n",
" )\n",
"\n",
" if apply_correction:\n",
" circuit = apply_correction_bit(circuit, qreg_data, creg_syndrome)\n",
"\n",
" circuit = apply_final_readout(circuit, qreg_data, creg_data)\n",
" return circuit\n",
"\n",
"\n",
"circuit = build_error_correction_sequence(apply_correction=True)\n",
"circuit.draw(output=\"mpl\", style=\"iqp\")"
]
},
{
"cell_type": "markdown",
"id": "609c0c47",
"metadata": {},
"source": [
"## Step 2. Optimize the problem for quantum execution\n",
"\n",
"To reduce the total job execution time, Qiskit primitives only accept circuits and observables that conforms to the instructions and connectivity supported by the target system (referred to as instruction set architecture (ISA) circuits and observables). [Learn more about transpilation.](/docs/guides/transpile)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "c8ea2716",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"### Generate ISA circuits"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "67b55eef",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<Image src=\"/docs/images/tutorials/repetition-codes/extracted-outputs/67b55eef-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
"\n",
"pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
"isa_circuit = pm.run(circuit)\n",
"\n",
"isa_circuit.draw(\"mpl\", style=\"iqp\", idle_wires=False)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "67acea4f",
"metadata": {},
"outputs": [],
"source": [
"no_correction_circuit = build_error_correction_sequence(\n",
" apply_correction=False\n",
")\n",
"\n",
"isa_no_correction_circuit = pm.run(no_correction_circuit)"
]
},
{
"cell_type": "markdown",
"id": "bcd61a1f",
"metadata": {},
"source": [
"## Step 3. Execute using Qiskit primitives"
]
},
{
"cell_type": "markdown",
"id": "e68d10d2",
"metadata": {},
"source": [
"Run the version with correction applied and one without correction."
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "d53319ba",
"metadata": {},
"outputs": [],
"source": [
"sampler_no_correction = Sampler(backend)\n",
"job_no_correction = sampler_no_correction.run(\n",
" [isa_no_correction_circuit], shots=1000\n",
")\n",
"result_no_correction = job_no_correction.result()[0]"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "df7421d0",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"sampler_with_correction = Sampler(backend)\n",
"job_with_correction = sampler_with_correction.run([isa_circuit], shots=1000)\n",
"result_with_correction = job_with_correction.result()[0]"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "1cba37f5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Data (no correction):\n",
"{'101': 70, '111': 840, '110': 45, '011': 27, '010': 10, '001': 4, '000': 4}\n",
"Syndrome (no correction):\n",
"{'00': 771, '01': 168, '10': 45, '11': 16}\n"
]
}
],
"source": [
"print(f\"Data (no correction):\\n{result_no_correction.data.data.get_counts()}\")\n",
"print(\n",
" f\"Syndrome (no correction):\\n{result_no_correction.data.syndrome.get_counts()}\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "7b7697f2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Data (corrected):\n",
"{'011': 52, '111': 723, '101': 162, '001': 6, '110': 23, '000': 18, '100': 9, '010': 7}\n",
"Syndrome (corrected):\n",
"{'00': 699, '01': 229, '10': 54, '11': 18}\n"
]
}
],
"source": [
"print(f\"Data (corrected):\\n{result_with_correction.data.data.get_counts()}\")\n",
"print(\n",
" f\"Syndrome (corrected):\\n{result_with_correction.data.syndrome.get_counts()}\"\n",
")"
]
},
{
"cell_type": "markdown",
"id": "1b652319",
"metadata": {},
"source": [
"## Step 4. Post-process, return result in classical format\n",
"\n",
"You can see that the bit flip code detected and corrected many errors; resulting in fewer errors overall."
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "fa59fb42",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"def decode_result(data_counts, syndrome_counts):\n",
" shots = sum(data_counts.values())\n",
" success_trials = data_counts.get(\"000\", 0) + data_counts.get(\"111\", 0)\n",
" failed_trials = shots - success_trials\n",
" error_correction_events = shots - syndrome_counts.get(\"00\", 0)\n",
" print(\n",
" f\"Bit flip errors were detected/corrected on {error_correction_events}/{shots} trials.\"\n",
" )\n",
" print(\n",
" f\"A final parity error was detected on {failed_trials}/{shots} trials.\"\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "5b1ff3a3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Completed bit code experiment data measurement counts (no correction): {'101': 70, '111': 840, '110': 45, '011': 27, '010': 10, '001': 4, '000': 4}\n",
"Completed bit code experiment syndrome measurement counts (no correction): {'00': 771, '01': 168, '10': 45, '11': 16}\n",
"Bit flip errors were detected/corrected on 229/1000 trials.\n",
"A final parity error was detected on 156/1000 trials.\n"
]
}
],
"source": [
"# non-corrected marginalized results\n",
"data_result = result_no_correction.data.data.get_counts()\n",
"marginalized_syndrome_result = result_no_correction.data.syndrome.get_counts()\n",
"\n",
"print(\n",
" f\"Completed bit code experiment data measurement counts (no correction): {data_result}\"\n",
")\n",
"print(\n",
" f\"Completed bit code experiment syndrome measurement counts (no correction): {marginalized_syndrome_result}\"\n",
")\n",
"decode_result(data_result, marginalized_syndrome_result)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "7f1c2d48",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Completed bit code experiment data measurement counts (corrected): {'011': 52, '111': 723, '101': 162, '001': 6, '110': 23, '000': 18, '100': 9, '010': 7}\n",
"Completed bit code experiment syndrome measurement counts (corrected): {'00': 699, '01': 229, '10': 54, '11': 18}\n",
"Bit flip errors were detected/corrected on 301/1000 trials.\n",
"A final parity error was detected on 259/1000 trials.\n"
]
}
],
"source": [
"# corrected marginalized results\n",
"corrected_data_result = result_with_correction.data.data.get_counts()\n",
"corrected_syndrome_result = result_with_correction.data.syndrome.get_counts()\n",
"\n",
"print(\n",
" f\"Completed bit code experiment data measurement counts (corrected): {corrected_data_result}\"\n",
")\n",
"print(\n",
" f\"Completed bit code experiment syndrome measurement counts (corrected): {corrected_syndrome_result}\"\n",
")\n",
"decode_result(corrected_data_result, corrected_syndrome_result)"
]
},
{
"cell_type": "markdown",
"id": "b66026c4",
"metadata": {},
"source": [
"## Tutorial survey\n",
"\n",
"Please take one minute to provide feedback on this tutorial. Your insights will help us improve our content offerings and user experience.\n",
"\n",
"[Link to survey](https://your.feedback.ibm.com/jfe/form/SV_5onAlfA2Y7ac1FA)"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"description": "This tutorial demonstrates how to build basic repetition codes using IBM dynamic circuits, an example of basic quantum error correction (QEC).",
"kernelspec": {
"display_name": "Python 3",
"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"
},
"platform": "cloud",
"title": "Repetition codes"
},
"nbformat": 4,
"nbformat_minor": 5
}