diff --git a/tutorials/QuantumErrorCorrection/Images/QEC_Shors_Code.png b/tutorials/QuantumErrorCorrection/Images/QEC_Shors_Code.png new file mode 100644 index 00000000000..112d5fdc5f9 Binary files /dev/null and b/tutorials/QuantumErrorCorrection/Images/QEC_Shors_Code.png differ diff --git a/tutorials/QuantumErrorCorrection/Images/QEC_of_bit_flip_using_three_qubits.png b/tutorials/QuantumErrorCorrection/Images/QEC_of_bit_flip_using_three_qubits.png new file mode 100644 index 00000000000..e1700a103ff Binary files /dev/null and b/tutorials/QuantumErrorCorrection/Images/QEC_of_bit_flip_using_three_qubits.png differ diff --git a/tutorials/QuantumErrorCorrection/Images/QEC_of_phase_flip_using_three_qubits.png b/tutorials/QuantumErrorCorrection/Images/QEC_of_phase_flip_using_three_qubits.png new file mode 100644 index 00000000000..0bf519c06d7 Binary files /dev/null and b/tutorials/QuantumErrorCorrection/Images/QEC_of_phase_flip_using_three_qubits.png differ diff --git a/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.csproj b/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.csproj new file mode 100644 index 00000000000..c36853e3c17 --- /dev/null +++ b/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.csproj @@ -0,0 +1,23 @@ + + + netcoreapp3.1 + x64 + Quantum.Kata.QuantumErrorCorrection + + + + + + + + + + + + + + + + + + diff --git a/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.ipynb b/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.ipynb new file mode 100644 index 00000000000..9986a6ad340 --- /dev/null +++ b/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.ipynb @@ -0,0 +1,574 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quantum Error Correction\n", + "\n", + "**Quantum error correction (QEC)** is used in quantum computing to protect quantum information from errors due to decoherence and other quantum noise. Quantum error correction is *essential* if one is to achieve fault-tolerant quantum computation that can deal not only with noise on stored quantum information, but also with faulty quantum gates, faulty quantum preparation, and faulty measurements.\n", + "\n", + "(You can read more about it [here]( https://en.wikipedia.org/wiki/Quantum_error_correction).) \n", + "\n", + "Classical error correction employs redundancy. The simplest way to reliably store information is to store it multiple times and if in future due to an unknown error it conflicst - just take a majority vote. However copying quantum information is not possible due to the [*no-cloning theorem*](https://en.wikipedia.org/wiki/No-cloning_theorem). The no-cloning theorem states that there is no Unitary Operation $U$ such that $\\forall |\\phi\\rangle$ $U|\\psi\\rangle|\\phi\\rangle = |\\phi\\rangle|\\phi\\rangle$. \n", + "In simpler terms it in impossible to create independent copies of an unknown quantum state. \n", + "\n", + "However the central idea of classical error correction which is to encode few logical bits of data into greater number of physical bits is still applicable in Quantum Computing and is the cornerstone of Quantum Error Correction.\n", + "\n", + "In this tutorial you will learn about:\n", + "* encoding one logical qubit into multiple physical qubits.\n", + "* guarding against a single bit flip error\n", + "* guarding against a single sign flip error\n", + "* implementing Shor's 9 qubit Error Correcting Code.\n", + "\n", + "Let's go!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To begin, first prepare this notebook for execution (if you skip the first step, you'll get \"Syntax does not match any known patterns\" error when you try to execute Q# code in the next cells; if you skip the second step, you'll get \"Invalid test name\" error):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%package Microsoft.Quantum.Katas::0.12.20070124" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> The package versions in the output of the cell above should always match. If you are running the Notebooks locally and the versions do not match, please install the IQ# version that matches the version of the `Microsoft.Quantum.Katas` package.\n", + ">
\n", + "> How to install the right IQ# version\n", + "> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.1.2.3, the installation steps are as follows:\n", + ">\n", + "> 1. Stop the kernel.\n", + "> 2. Uninstall the existing version of IQ#:\n", + "> dotnet tool uninstall microsoft.quantum.iqsharp -g\n", + "> 3. Install the matching version:\n", + "> dotnet tool install microsoft.quantum.iqsharp -g --version 0.1.2.3\n", + "> 4. Reinstall the kernel:\n", + "> dotnet iqsharp install\n", + "> 5. Restart the Notebook.\n", + ">
\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%workspace reload" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Basics:\n", + "\n", + "The following section provides a brief Introduction of the Basics of Quantum Error Correction - the notation, basic ideas and error correction schemes." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Types of Error\n", + "\n", + "In Classical Bits the only possible states are $0$ and $1$. Hence the only kind of error is a bit flip error. This error involves a bit randomly flipping: $0 \\rightarrow 1$ or $1 \\rightarrow 0$. Such an error can be modelled by randomly applying a $NOT$ gate to a bit. Classically these errors are often detected and corrected by introducing duplication of data and parity check bits. \n", + "\n", + "In Quantum Computing, the possible errors are not limited to bit flips, but also include sign flips (or phase flips). The most general error can be thought of as a Unitary $E$ applied to a qubit. \n", + "\n", + "A single qubit Unitary $U$ can be represented as a linear combination of the *Pauli Matrices* $\\{\\sigma_I,\\sigma_X,\\sigma_Y,\\sigma_Z\\}$. \n", + "\n", + "$$U = c_I\\sigma_I + c_X\\sigma_X + c_Y\\sigma_Y + c_Z\\sigma_Z$$\n", + "\n", + "where the coefficients $c_I,c_X,c_Y,c_Z$ are complex numbers satisfying the following conditions:\n", + "$$|c_I|^2+|c_X|^2+|c_Y|^2+|c_Z|^2,$$\n", + "$$\\mathcal{R}(c_Ic_X*) + \\mathcal{I}(c_Yc_Z*) = 0,$$\n", + "$$\\mathcal{R}(c_Ic_Y*) + \\mathcal{I}(c_Xc_Z*) = 0,$$\n", + "$$\\mathcal{R}(c_Ic_Z*) + \\mathcal{I}(c_Xc_Y*) = 0,$$\n", + "where $\\mathcal{R},\\mathcal{I}$ are the Real and Imaginary Components respectively. \n", + "\n", + "$\\sigma_Y$ can also be represnted in terms of $\\sigma_X$ and $\\sigma_Z$, since $\\sigma_Y = i\\sigma_X\\sigma_Z$. Hence we can rewrite the Unitary $U$ as $c_I\\sigma_I + c_X\\sigma_X + c_Z\\sigma_Z + c_{XZ}\\sigma_X\\sigma_Z$. A circuit which can correct all errors in the following group $\\{I,X,Z,XZ\\}$ can correct any single qubit error due to linearity." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Encoding Logical Qubits into Physical Qubits\n", + "\n", + "In classical computing, the bit can only be in the states $0$ and $1$. These states form the 2 logical states for classical computation. Error Correction involves duplicating these logical bits into multiple physical bits in order to make classical computing more fault-tolerant. In classical error correction $k$ physical bits can be used to represent $n$ logical bits where $k\\geq n$. A famous example of such an encoding scheme is the [Hamming(7,4) Scheme](https://en.wikipedia.org/wiki/Hamming(7,4)) where 7 bits are used to encode 4 logical bits.\n", + "\n", + "The *no cloning theorem* prevent the duplication of qubit. However we can store a logical qubit using multiple physical qubits. Henceforth we shall denote a logical qubit with the subscript $_L$. Thus the computational basis states of a single logical qubits would be denotes as $|0\\rangle_L$ and $|1\\rangle_L$. \n", + "\n", + "The **encoding scheme** is thus a *mapping* from logical qubits to physical qubits. \n", + "$$E: |\\psi_i\\rangle_L \\rightarrow |\\phi_i\\rangle$$ \n", + "The mapping encoding $n$ logical qubits into $k$ physical qubits, is a linear transformation $T: \\{0,1\\}_L^n \\rightarrow \\{0,1\\}^k$. It is a mapping from a subspace of dimension $2^n$ to a subspace of dimension $2^k$. \n", + "\n", + "This encoding is a quantum channel which is realised using $k-n$ ancillary qubits. The Unitary Operation is \n", + "$$U_E: |\\psi_i\\rangle_L|0...0\\rangle \\rightarrow |\\phi_i\\rangle$$ or in vector space terms - $U_T: \\{0,1\\}_L^n\\{0\\}^{k-n} \\rightarrow \\{0,1\\}^k$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Hamming Distance and Error Correction \n", + "\n", + "The **Hamming Distance** $\\mathcal{D}(s_1,s_2)$ between 2 bit strings $s_1$ and $s_2$ of size $n$ is defined as the minimum number of Bit-Flips required to convert $s_1$ to $s_2$. \n", + "Let $E: |\\psi_i\\rangle_L \\rightarrow |\\phi_i\\rangle$ denote an encoding scheme which *maps* logical qubits into physical qubits and $U_{Error}$ denote a possible error which results in $|\\phi_i\\rangle$ being converted to $|\\phi_i'\\rangle$. \n", + "This encoding scheme only guards $|\\phi_i\\rangle$ against the error $U_{Error}$ as long as the Hamming Distance $\\mathcal{D}(\\psi_i,\\psi_i') < \\mathcal{D}(\\psi_j,\\psi_i')$ $\\forall j$.\n", + "\n", + "Thus successfull error correction depends on the fact that even after small error the Hamming Distance $\\mathcal{D}$ of modified state and initial state is less than the Hamming Distance $\\mathcal{D}$ of modified state and all other initial states. \n", + "\n", + "The classical [repetition code](https://en.wikipedia.org/wiki/Repetition_code) creates n copies of a single bit. Such a code can correct upto $d=\\lfloor\\frac{n-1}{2}\\rfloor$ errors. \n", + "In Error Correction notation an encoding scheme which encodes $n$ logical qubits into $k$ physical qubits which can guard against $d$ errors is denoted as a **$(n,k,d)$ encoding scheme**." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 1: Correcting Bit Flip Errors\n", + "\n", + "The Bit Flip Error is one of the simplest errors. It involves the random application of $X$ gate. We assume that a $X$ gate may or may not be applied to a single physical qubit. To protect against this error we shall encode a single logical qubit $|\\psi\\rangle_L = \\alpha|0\\rangle_L + \\beta|1\\rangle_L$ into 3 physical qubits. We shall undo the encoding and in case of an error take the majority vote." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 1.1: Encoding Logical Qubit I\n", + "\n", + "**Input:** A `logical` qubit in the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$ and two qubits in `ancillaryRegister`.\n", + "\n", + "**Goal:** Create a state $|\\phi\\rangle = \\alpha|000\\rangle + \\beta|111\\rangle$ on these qubits.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T11_BitFlipEncoding_Test\n", + "\n", + "operation BitFlipEncoding (logical: Qubit, ancillaryRegister : Qubit[]) : Unit {\n", + " CNOT(logical, ancillaryRegister[0]);\n", + " CNOT(logical, ancillaryRegister[1]);\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 1.2: Correct Bit Flip Error\n", + "\n", + "**Input:** An $X$ gate may be randomly applied to one of 3 qubits from Task 1.1. The resulting state is given as an input.\n", + "\n", + "**Goal:** Transform `register[0]` into the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$. You may do anything you wish to the other 2 qubits. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T12_CorrectBitFlip_Test\n", + "\n", + "operation CorrectBitFlip (register : Qubit[]) : Unit {\n", + " BitFlipEncoding(register[0], register[1..2]); // Repeat Task 1.1 to unentangle the qubits.\n", + " CCNOT(register[1],register[2],register[0]); // Use CCNOT to fix the state of the 1st qubit.\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 1.3: Detect Error Location\n", + "\n", + "**Input:** An $X$ gate may be randomly applied to one of 3 qubits from Task 1.1. The resulting state is given as an input.\n", + "\n", + "**Goal:** \n", + "* Transform `register[0]` into the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$. \n", + "* Find the location of the bit flip error i.e on which qubit - 1, 2 or 3 the $X$ gate was applied. If $X$ gate wasn't applied then return 0. \n", + "* Reset the other 2 qubits to state $|00\\rangle$.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T13_DetectErrorLocation_Test\n", + "\n", + "open Microsoft.Quantum.Measurement;\n", + "\n", + "operation DetectErrorLocation (register : Qubit[]) : Int {\n", + " CorrectBitFlip(register); // Correct 1st Qubit\n", + " let bit2 = MResetZ(register[1])==One? true | false; // Reset to state 0\n", + " let bit3 = MResetZ(register[2])==One? true | false; // Reset to state 1\n", + " \n", + " // Location Logic\n", + " if (bit2 && bit3){\n", + " return 1; \n", + " } else if (bit2 || bit3) {\n", + " return bit2? 2 | 3;\n", + " } else {\n", + " return 0;\n", + " }\n", + " \n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 1.4: Detect and Fix a Bit Flip Error\n", + "\n", + "**Input:** A `logical` qubit in the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$. An $`operation BitError (register: Qubit[]) :Unit` implementing $E_{bit}$ which denotes a possible Bit-Flip applied to any of the 3 qubits. \n", + "\n", + "**Goal:** Detect and Fix the Error which is applied by the `operation BitError(register: Qubit[]) :Unit`. \n", + "At the end of the task the `logical` qubit should be in the same state as before. Additionally you must find out whether or not a bit flip occured and if it did - what was its location. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T14_DetectFixBitFlipError_Test\n", + "\n", + "operation DetectFixBitFlipError (logical: Qubit, BitError : (Qubit[] => Unit)) : Int {\n", + " using(ancillaryRegister = Qubit[2]){\n", + " BitFlipEncoding(logical,ancillaryRegister); // Encoding the Logical Qubits into Physical Qubits\n", + " let register = [logical]+ancillaryRegister; \n", + " BitError(register); // Introducing Possible Bit Error in the register\n", + " return DetectErrorLocation(register); // Fix the Logical Qubit, Detect Error Location and Reset Ancillary Qubit to 00\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"QEC\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 2: Correcting Sign Flip Errors\n", + "\n", + "The Phase Flip Error is unique since it has no classical counterpart. It involves the random application of $Z$ gate. We assume that a $Z$ gate may or may not be applied to a single physical qubit. We already know how to correct bitflip errors. If we could transform $E_{phase}$ into $E_{bit}$, we could re-use the Bit Flip Error Correction Code to create a Sign Flip Error Correction Code." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 2.1: Convert Z into X\n", + "\n", + "**Input:** A qubit in the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$.\n", + "\n", + "**Goal:** Apply the $X$ gate on this qubit without using the [`X`](https://docs.microsoft.com/en-us/qsharp/api/qsharp/microsoft.quantum.intrinsic.x). \n", + "\n", + "
\n", + "
\n", + " Need a hint? Click here\n", + " Find $U$ such that $X$ = $U^{\\dagger}ZU$. \n", + "
\n", + "\n", + "
\n", + "
\n", + " Need another hint? Click here\n", + " $Z|\\pm\\rangle = |\\mp\\rangle$ \n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T21_ConvertZToX_Test\n", + "\n", + "operation ConvertZToX (q: Qubit) : Unit {\n", + " ApplyWith(H,Z,q); //Applies H†ZH on q\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 2.2: Convert Phase Flip Error Into BitFlip Error\n", + "\n", + "**Input:** An `operation PhaseError (register: Qubit[]) :Unit` implementing $E_{phase}$ which denotes a possible Phase-Flip applied to any of the 3 qubits. \n", + "\n", + "**Goal:** Return an `operation` which Convert the possible Phase-Flip applied in `operation PhaseError` into a Bit-Flip." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T22_ConvertPhaseFlipToBitFlipError_Test\n", + "\n", + "operation ConvertPhaseFlipToBitFlipError (PhaseFlip : (Qubit[] => Unit)) : (Qubit[] => Unit) {\n", + " let ConvertToHadamard = ApplyToEachA(H,_);// Convert Qubits to Hadamard Basis\n", + " return ApplyWith(ConvertToHadamard, PhaseFlip, _);// A Phase Flip in Hadamard Basis is essentially a Bit-Flip\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 2.3: Detect and Fix a Phase Flip Error\n", + "\n", + "**Input:** A `logical` qubit in the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$. An $`operation PhaseError (register: Qubit[]) :Unit` which implements $E_{phase}$ denoting a possible Phase-Flip applied to any of the 3 qubits. \n", + "\n", + "**Goal:** Detect and Fix the Error which is applied by the `operation PhaseError(register: Qubit[]) :Unit`. \n", + "At the end of the task the `logical` qubit should be in the same state as before. Additionally you must find out whether or not a bit flip occured and if it did - what was its location. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T23_DetectFixPhaseFlipError_Test\n", + "\n", + "operation DetectFixPhaseFlipError (logical: Qubit, PhaseError : (Qubit[] => Unit)) : Int {\n", + " let BitError = ConvertPhaseFlipToBitFlipError(PhaseError); // Converted The PhaseError to BitError\n", + " return DetectFixBitFlipError(logical, BitError); // Fixed the BitError\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"QEC\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 3: Correcting Arbitrary One Qubit Errors - Shor's Code\n", + "\n", + "We required 3 qubits to correct a possible Bit-Flip Error and 3 qubits to correct a possible Sign-Qubit Error. \n", + "Correcting these errors involved an encoding scheme where a single logical qubit was encoded into 3 physical qubits. \n", + "The Bit Flip Encoding Scheme was:\n", + "$$|0\\rangle_L \\rightarrow_{Bit} |000\\rangle_L,$$\n", + "$$|1\\rangle_L \\rightarrow_{Bit} |111\\rangle_L$$\n", + "In this encoding scheme a single Bit-Flip could be detected since the Hamming Distance of $000$ with any one of $\\{100,010,001\\}$ is smaller than the the Hamming Distance of $111$ with any one of $\\{100,010,001\\}$ or $\\{-++,+-+,++-\\}$.\n", + "\n", + "The Phase Flip Encoding Scheme involving applying Hadamard's to all qubits after using Bit Flip Encoding Scheme:\n", + "$$|0\\rangle_L \\rightarrow_{Phase} |+++\\rangle_L,$$\n", + "$$|1\\rangle_L \\rightarrow_{Phase} |---\\rangle_L$$\n", + "This was simulated by transforming the $E_{phase}$ into an equivalent $E_{bit}$.\n", + "Similarly, in this scheme a single Phase-Flip could be detected since the Hamming Distance of $+++$ with any one of $\\{-++,+-+,++-\\}$ is smaller than the the Hamming Distance of $---$ with any one of $\\{100,010,001\\}$ or $\\{-++,+-+,++-\\}$.\n", + "\n", + "In Shor's encoding scheme 9 qubits are used to encode a single logical qubit. This scheme protects against Sign-Flip as well as Bit-Flip Errors. As we previously discussed any scheme which protects against all errors in $\\{I,X,Z,XY\\}$ will due to linearity protect against an arbitrary single qubit errors. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 3.1: Encoding Logical Qubit II\n", + "\n", + "**Input:** A `logical` qubit in the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$ and eight qubits in `ancillaryRegister`.\n", + "\n", + "**Goal:** Create a state $|\\phi\\rangle = \\alpha|0\\rangle_L + \\beta|1\\rangle_L$ on these qubits where \n", + "\n", + "$$|0\\rangle_L = \\frac {1}{2\\sqrt{2}}(|000\\rangle +|111\\rangle )\\otimes (|000\\rangle +|111\\rangle )\\otimes (|000\\rangle +|111\\rangle )$$\n", + "$$|1\\rangle_L =\\frac {1}{2\\sqrt{2}}(|000\\rangle -|111\\rangle )\\otimes (|000\\rangle -|111\\rangle )\\otimes (|000\\rangle -|111\\rangle )$$\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "operation GroupEncoding(register: Qubit[]) : Unit {\n", + " BitFlipEncoding(register[0], register[1..2]); // Applying the Bit Flip Encoding on 3 qubits.\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T31_ShorEncoding_Test\n", + "\n", + "operation ShorEncoding (logical: Qubit, ancillaryRegister : Qubit[]) : Unit {\n", + " let outerGroup = [logical,ancillaryRegister[2],ancillaryRegister[5]]; // The outer correction qubits \n", + " GroupEncoding(outerGroup); // Applying the Encoding on 1st, 4th and 7th qubits.\n", + " ApplyToEach(H,outerGroup); // Converting 1st,4th and 7th qubits to Hadamard basis\n", + " GroupEncoding([logical]+ancillaryRegister[0..1]); // Applying the Encoding on 1st Inner Group of qubits.\n", + " GroupEncoding(ancillaryRegister[2..4]); // Applying the Encoding on 2nd Inner Group of qubits.\n", + " GroupEncoding(ancillaryRegister[5..7]); // Applying the Encoding on 3rd Inner Group of qubits.\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 3.2: Detect and Correct Single Qubit Error\n", + "\n", + "**Input:** An unknown unitary $U$ which is one among $\\{X,Z,XZ\\}$ may be randomly applied to one of 9 qubits from Task 3.1. The resulting state is given as an input.\n", + "\n", + "**Goal:** \n", + "* Transform `register[0]` into the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$. \n", + "* Find the type of the single qubit error i.e which among $\\{I,X,Z,XZ\\}$ gate was applied. \n", + "The result will be an integer denoting error type - $I$ is 0, $X$ is 1, $Z$ is 2, $XZ$ is 3.\n", + "* Reset the other 8 qubits to state $|00000000\\rangle$.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T32_DetectSingleQubitErrorLocation_Test\n", + "\n", + "open Microsoft.Quantum.Arrays;\n", + "\n", + "operation DetectSingleQubitErrorLocation (register : Qubit[]) : Int {\n", + " // Apply Bit Flip Error Correction to 3 Inner Groups\n", + " let innerGroups = Partitioned([3,3,3],register) // Partition register into 3 Inner Groups\n", + " // Bit Flip Error Correction and Detection of 3 Inner Groups\n", + " // Find out if a Bit Flip Error was corrected.\n", + " let innerGroupErrorBit = (Max(Mapped(DetectErrorLocation,innerGroups))>0)? 1 | 0; \n", + " \n", + " // All Z Errors have passed through. \n", + " let outerGroup = register[0..3..6];\n", + " ApplyToEach(H, outerGroup); // Convert Z errors into X errors.\n", + " // Find out if a Phase Flip Error was corrected.\n", + " let outerGroupErrorBit = (DetectErrorLocation(outerGroup)>0)? 1| 0; \n", + " let answer = outerGroupErrorBit*2 + innerGroupErrorBit;\n", + " return answer;\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 3.3: Fix Arbitrary Single Qubit Error\n", + "\n", + "**Input:** A `logical` qubit in the state $|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle$. An $`operation SingleQubitError (register: Qubit[]) :Unit` implementing $E$ which denotes a possible arbitrary Single Qubit Error applied to any of the 9 qubits. \n", + "\n", + "**Goal:** Fix the Error which is applied by the `operation SingleQubitError(register: Qubit[]) :Unit`. \n", + "At the end of the task the `logical` qubit should be in the same state as before. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "operation GroupDecoding(register: Qubit[]) : Unit {\n", + " GroupEncoding(register[0], register[1..2]); // Applying the Bit Flip Encoding on 3 qubits.\n", + " CCNOT(register[1],register[2],register[0]); // Using CCNOT to fix 1st qubit.\n", + "}\n", + "\n", + "operation ShorDecoding(register: Qubit[]) : Unit{\n", + " let innerGroups = Partitioned([3,3,3],register) // Partition register into 3 Inner Groups\n", + " ApplyToEach(GroupDecoding, innerGroups); // Decode Inner Qubits \n", + " let outerGroup = register[0..3..6]; // The outer correction qubits \n", + " ApplyToEach(H,outerGroup); // Converting 1st,4th and 7th qubits back to Computational basis\n", + " GroupDecoding(outerGroup); // Decode Outer Qubits.\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%kata T33_FixArbitrarySingleQubitError_Test\n", + "\n", + "open Microsoft.Quantum.Measurement;\n", + "open Microsoft.Quantum.Arrays;\n", + "\n", + "operation FixArbitrarySingleQubitError (logical: Qubit, SingleQubitError : (Qubit[] => Unit)) : Unit {\n", + " using(ancillaryRegister = Qubit[8]){\n", + " ShorEncoding(logical,ancillaryRegister); // Encoding the Logical Qubits into Physical Qubits\n", + " let register = [logical]+ancillaryRegister; \n", + " SingleQubitError(register); // Introducing Possible Bit Error in the register\n", + " ShorDecoding(register); // Decoding the Physical Qubits into Logical Qubits\n", + " let results = Mapped(MResetZ, ancillaryRegister); // Measure and then Reset them back to state 0\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"QEC\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "Congratulations on completing the Quantum Error Correction Kata! We hope you enjoyed this tutorial on quantum error correction ! If you're looking to learn more about quantum computing and Q# checkout other Katas.\n", + "\n", + "The [Quantum Katas](https://github.com/microsoft/QuantumKatas/) are sets of programming exercises on quantum computing that can be solved using Q#. They cover a variety of topics, from the basics like the concepts of superposition and measurements to more interesting algorithms like Grover's search." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Q#", + "language": "qsharp", + "name": "iqsharp" + }, + "language_info": { + "file_extension": ".qs", + "mimetype": "text/x-qsharp", + "name": "qsharp", + "version": "0.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.sln b/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.sln new file mode 100644 index 00000000000..5af1fcbf6f9 --- /dev/null +++ b/tutorials/QuantumErrorCorrection/QuantumErrorCorrection.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantumErrorCorrection", "QuantumErrorCorrection.csproj", "{B4477C91-FBD6-4DCE-8B4C-1A5E48669790}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "..\..\utilities\Common\Common.csproj", "{BC099DCB-6526-49CF-8638-0132C9C5AE89}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Release|Any CPU.Build.0 = Release|Any CPU + {BC099DCB-6526-49CF-8638-0132C9C5AE89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC099DCB-6526-49CF-8638-0132C9C5AE89}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC099DCB-6526-49CF-8638-0132C9C5AE89}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC099DCB-6526-49CF-8638-0132C9C5AE89}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F23513ED-2103-49D7-9F64-7BA3199FC689} + EndGlobalSection +EndGlobal diff --git a/tutorials/QuantumErrorCorrection/README.md b/tutorials/QuantumErrorCorrection/README.md new file mode 100644 index 00000000000..5d559e53f05 --- /dev/null +++ b/tutorials/QuantumErrorCorrection/README.md @@ -0,0 +1,10 @@ +# Welcome! + +This folder contains a Notebook tutorial on Quantum Error Correction - +an application of quantum computing that is used in quantum computing to protect quantum information from errors due to decoherence and other quantum noise. + +You can run the tutorial online [here](https://mybinder.org/v2/gh/Microsoft/QuantumKatas/master?filepath=tutorials/QuantumErrorCorrection%2FQuantumErrorCorrection.ipynb). Alternatively, you can install Jupyter and Q# on your machine, as described [here](https://docs.microsoft.com/quantum/install-guide/jupyter), and run the tutorial locally by navigating to this folder and starting the notebook from command line using the following command: + + jupyter notebook QuantumErrorCorrection.ipynb + +The Q# project in this folder contains the back-end of the tutorial and is not designed for direct use. diff --git a/tutorials/QuantumErrorCorrection/ReferenceImplementation.qs b/tutorials/QuantumErrorCorrection/ReferenceImplementation.qs new file mode 100644 index 00000000000..d4373d7e871 --- /dev/null +++ b/tutorials/QuantumErrorCorrection/ReferenceImplementation.qs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +////////////////////////////////////////////////////////////////////// +// This file contains reference solutions to all tasks. +// You should not modify anything in this file. +// We recommend that you try to solve the tasks yourself first, +// but feel free to look up the solution if you get stuck. +////////////////////////////////////////////////////////////////////// + +namespace Quantum.Kata.QuantumErrorCorrection { + + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Measurement; + open Microsoft.Quantum.Math; + + + // Exercise 1. + operation Untitled_Reference () : Int { + return 0; + } +} \ No newline at end of file diff --git a/tutorials/QuantumErrorCorrection/Tasks.qs b/tutorials/QuantumErrorCorrection/Tasks.qs new file mode 100644 index 00000000000..ff2cf3f9bac --- /dev/null +++ b/tutorials/QuantumErrorCorrection/Tasks.qs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +////////////////////////////////////////////////////////////////// +// This file is a back end for the tasks in Deutsch-Jozsa algorithm tutorial. +// We strongly recommend to use the Notebook version of the tutorial +// to enjoy the full experience. +////////////////////////////////////////////////////////////////// + +namespace Quantum.Kata.QuantumErrorCorrection { + + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + + // Exercise 1. + operation Untitled() : Int { + return 0; + } +} \ No newline at end of file diff --git a/tutorials/QuantumErrorCorrection/TestSuiteRunner.cs b/tutorials/QuantumErrorCorrection/TestSuiteRunner.cs new file mode 100644 index 00000000000..14f1489a26b --- /dev/null +++ b/tutorials/QuantumErrorCorrection/TestSuiteRunner.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +////////////////////////////////////////////////////////////////////// +// This file contains parts of the testing harness. +// You should not modify anything in this file. +// The tasks themselves can be found in Tasks.qs file. +////////////////////////////////////////////////////////////////////// + +using System.Diagnostics; + +using Microsoft.Quantum.Katas; +using Microsoft.Quantum.Simulation.XUnit; + +using Xunit.Abstractions; + + +namespace Quantum.Kata.QuantumErrorCorrection +{ + public class TestSuiteRunner + { + private readonly ITestOutputHelper output; + + public TestSuiteRunner(ITestOutputHelper output) + { + this.output = output; + } + + /// + /// This driver will run all Q# tests (operations named "...Test") + /// that belong to namespace Quantum.Kata.QuantumErrorCorrection. + /// + [OperationDriver(TestNamespace = "Quantum.Kata.QuantumErrorCorrection")] + public void TestTarget(TestOperation op) + { + using (var sim = new CounterSimulator()) + { + // OnLog defines action(s) performed when Q# test calls function Message + sim.OnLog += (msg) => { output.WriteLine(msg); }; + sim.OnLog += (msg) => { Debug.WriteLine(msg); }; + op.TestOperationRunner(sim); + } + } + } +} diff --git a/tutorials/QuantumErrorCorrection/Tests.qs b/tutorials/QuantumErrorCorrection/Tests.qs new file mode 100644 index 00000000000..a6557813841 --- /dev/null +++ b/tutorials/QuantumErrorCorrection/Tests.qs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +////////////////////////////////////////////////////////////////////// +// This file contains testing harness for all tasks. +// You should not modify anything in this file. +////////////////////////////////////////////////////////////////////// + +namespace Quantum.Kata.QuantumErrorCorrection { + + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Arrays; + open Quantum.Kata.Utils; + + + // Exercise 1. + operation T1_Untitiled () : Unit { + Message("Testing..."); + } +} \ No newline at end of file