microsoft/qdk
Publicmirrored fromhttps://github.com/microsoft/qdkAvailable
samples/algorithms/BitFlipCode.qs
132lines · modecode
| 1 | /// # Sample |
| 2 | /// Bit-Flip Code |
| 3 | /// |
| 4 | /// # Description |
| 5 | /// This sample demonstrates the three-qubit bit-flip code. This code is a |
| 6 | /// simple quantum error correction strategy for protecting against a single |
| 7 | /// bit-flip error by encoding a logical qubit into three physical qubits. A |
| 8 | /// single bit-flip error is when one of the three physical qubits has its |
| 9 | /// state changed erroneously in a way that is equivalent to applying the X |
| 10 | /// gate to it. |
| 11 | /// |
| 12 | /// The bit-flip correction code works by checking the parity of the physical |
| 13 | /// qubits. By measuring only their parity, the quantum superposition of the |
| 14 | /// qubits is preserved. Because all the physical qubits are supposed to have |
| 15 | /// the same state, when the parity checks detect a difference in state, the |
| 16 | /// erroneous qubit can be identified and corrected. |
| 17 | /// |
| 18 | /// This Q# program prepares a logical qubit encoded as three physical qubits |
| 19 | /// with one of the qubits being bit-flipped. It then identifies and corrects |
| 20 | /// the flipped qubit. |
| 21 | import Std.Math.*; |
| 22 | import Std.Random.*; |
| 23 | import Std.Arrays.*; |
| 24 | import Std.Diagnostics.*; |
| 25 | import Std.Measurement.*; |
| 26 | |
| 27 | operation Main() : Result { |
| 28 | use logicalQubit = Qubit[3]; |
| 29 | |
| 30 | // Set the initial state of the first physical qubit. |
| 31 | SetSampleState(logicalQubit[0]); |
| 32 | |
| 33 | // Using two additional qubits, encode the first physical qubit into a |
| 34 | // logical qubit. |
| 35 | EncodeAsLogicalQubit(logicalQubit[0], logicalQubit[1...]); |
| 36 | |
| 37 | // Induce a bit-flip error on a random qubit. |
| 38 | X(logicalQubit[DrawRandomInt(0, 2)]); |
| 39 | |
| 40 | // Show the logical qubit with the error state. |
| 41 | DumpMachine(); |
| 42 | |
| 43 | // Find and correct the bit-flip error. |
| 44 | CorrectError(logicalQubit); |
| 45 | |
| 46 | // Show the logical qubit with the corrected state. |
| 47 | DumpMachine(); |
| 48 | |
| 49 | // Decode the logical qubit back into a single physical qubit. |
| 50 | Adjoint EncodeAsLogicalQubit(logicalQubit[0], logicalQubit[1...]); |
| 51 | |
| 52 | // Measure and reset the physical qubit before releasing it. |
| 53 | let result = M(logicalQubit[0]); |
| 54 | Reset(logicalQubit[0]); |
| 55 | return result; |
| 56 | } |
| 57 | |
| 58 | /// # Summary |
| 59 | /// This operation sets the state of the given qubit such that |
| 60 | /// it will have a 20% likelihood of resulting in a `Zero` and |
| 61 | /// 80% likelihood of resulting in a `One` when measured in the |
| 62 | /// computational basis. The input qubit is expected to be in |
| 63 | /// the |0〉 state. |
| 64 | /// |
| 65 | /// # Input |
| 66 | /// ## q |
| 67 | /// The given qubit to be put into superposition. It is assumed that this |
| 68 | /// qubit is in its default |0〉 state. |
| 69 | operation SetSampleState(q : Qubit) : Unit { |
| 70 | let alpha = 0.20; |
| 71 | Ry(2.0 * ArcCos(Sqrt(alpha)), q); |
| 72 | } |
| 73 | |
| 74 | /// # Summary |
| 75 | /// This operation takes the given `physicalQubit` state, |
| 76 | /// (α|0〉 + β|1〉) / √2, and encodes it in the `aux` qubits. This |
| 77 | /// encodes all the qubits into a single logical qubit whose state reflects |
| 78 | /// the state of the given `physicalQubit`: (α|000〉 + β|111〉) / √2. |
| 79 | /// |
| 80 | /// # Input |
| 81 | /// ## physicalQubit |
| 82 | /// The qubit whose state, (α|0〉 + β|1〉) / √2, is to be encoded in the |
| 83 | /// logical qubit. |
| 84 | /// |
| 85 | /// ## aux |
| 86 | /// The auxiliary qubits that will be used as part of the encoding. These |
| 87 | /// should be grouped with the `physicalQubit` to form the logical qubit. |
| 88 | operation EncodeAsLogicalQubit(physicalQubit : Qubit, aux : Qubit[]) : Unit is Adj { |
| 89 | ApplyToEachA(CNOT(physicalQubit, _), aux); |
| 90 | } |
| 91 | |
| 92 | /// # Summary |
| 93 | /// This operation detects and corrects a single bit-flip error for a logical |
| 94 | /// qubit encoded as three physical qubits. When finished, the given register |
| 95 | /// of qubits will be in the state: (α|000〉 + β|111〉) / √2. |
| 96 | /// |
| 97 | /// # Input |
| 98 | /// ## logicalQubit |
| 99 | /// The given register of three physical qubits representing a single logical qubit |
| 100 | /// having superposition (α|0〉 + β|1〉) / √2. |
| 101 | /// This logical qubit can have up to one bit-flip error that will be corrected. |
| 102 | operation CorrectError(logicalQubit : Qubit[]) : Unit { |
| 103 | Fact(Length(logicalQubit) == 3, "`logicalQubit` must be length 3"); |
| 104 | |
| 105 | // Entangle the parity of the physical qubits into two auxiliary qubits. |
| 106 | use aux = Qubit[2]; |
| 107 | CNOT(logicalQubit[0], aux[0]); |
| 108 | CNOT(logicalQubit[1], aux[0]); |
| 109 | CNOT(logicalQubit[1], aux[1]); |
| 110 | CNOT(logicalQubit[2], aux[1]); |
| 111 | |
| 112 | // Measure the parity information from the auxiliary qubits. |
| 113 | let (parity01, parity12) = (M(aux[0]), M(aux[1])); |
| 114 | ResetAll(aux); |
| 115 | |
| 116 | // Determine which of the three qubits has the error based on the |
| 117 | // parity measurements. |
| 118 | let indexOfError = if (parity01, parity12) == (One, Zero) { |
| 119 | 0 |
| 120 | } elif (parity01, parity12) == (One, One) { |
| 121 | 1 |
| 122 | } elif (parity01, parity12) == (Zero, One) { |
| 123 | 2 |
| 124 | } else { |
| 125 | -1 |
| 126 | }; |
| 127 | |
| 128 | // If an error was detected, correct that qubit. |
| 129 | if indexOfError > -1 { |
| 130 | X(logicalQubit[indexOfError]); |
| 131 | } |
| 132 | } |
| 133 | |