diff --git a/samples/error-correction/bit-flip-code/BitFlipCode.csproj b/samples/error-correction/bit-flip-code/BitFlipCode.csproj
index b99d02881cd1..b1c3611ce958 100644
--- a/samples/error-correction/bit-flip-code/BitFlipCode.csproj
+++ b/samples/error-correction/bit-flip-code/BitFlipCode.csproj
@@ -4,6 +4,7 @@
Exe
netcoreapp3.0
x64
+ 8.0
diff --git a/samples/error-correction/bit-flip-code/BitFlipCode.qs b/samples/error-correction/bit-flip-code/BitFlipCode.qs
index efc7a1c922a8..b2c0e6ed052c 100644
--- a/samples/error-correction/bit-flip-code/BitFlipCode.qs
+++ b/samples/error-correction/bit-flip-code/BitFlipCode.qs
@@ -1,60 +1,62 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+
namespace Microsoft.Quantum.Samples.BitFlipCode {
open Microsoft.Quantum.ErrorCorrection;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Math;
-
-
+ open Microsoft.Quantum.Arrays;
+
+
//////////////////////////////////////////////////////////////////////////
// Introduction //////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-
+
// In this sample, we build on the discussion in the quantum error
// correction section of the developers' guide:
-
- // https://docs.microsoft.com/en-us/quantum/libraries/error-correction
-
+
+ // https://docs.microsoft.com/quantum/libraries/error-correction
+
// In particular, we start by manually encoding into the bit-flip code.
// We then show how operations and functions provided in the Q# canon
// allow us to easily model error correction in a way that immediately
// generalizes to other codes.
-
+
//////////////////////////////////////////////////////////////////////////
// The Bit-Flip Code /////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-
+
// The bit-flip code protects against any one bit-flip (X) error on three
// qubits by mapping |0〉 to |̅0〉 ≔ |000〉 and |1〉 to |̅1〉 ≔ |111〉. By
// linearity, any other state |ψ〉 = α|0〉 + β|1〉 is represented by the
// logical state
-
+
// |̅ψ〉 ≔ α |̅0〉 + β |̅1〉
// = α |000〉 + β |111〉.
-
+
// We start by defining an operation which implements an encoder for
// this code. To do so, note that CNOT allows us to "copy" classical
// information in the bitstrings used to label computational basis
// elements:
-
+
// CNOT |b0〉 = |bb〉,
-
+
// where b ∈ {0, 1}. This is not the same as copying the state, since
// CNOT acts linearly:
-
+
// CNOT (α |0〉 + β |1〉) ⊗ |0〉 = α |00〉 + β |11〉.
-
+
// That is, consistent with the no-cloning theorem, CNOT did not
// copy our arbitrary input state. On the other hand, this is
// precisely the transformation that we want here:
-
+
// CNOT₀₂ · CNOT₀₁ (α |0〉 + β |1〉) ⊗ |00〉
// = α |000〉 + β |111〉
// = α |̅0〉 + β |̅1〉.
-
+
// Thus, we can write out our encoder in a very simple form:
-
+
/// # Summary
/// Given a qubit representing a state to be protected and two auxiliary
/// qubits initially in the |0〉 state, encodes the state into the
@@ -66,7 +68,7 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
/// ## auxiliaryQubits
/// Two qubits, initially in the |00〉 state, to be used in protecting
/// the state of `data`.
- operation EncodeIntoBitFlipCode (data : Qubit, auxiliaryQubits : Qubit[]) : Unit
+ operation EncodeIntoBitFlipCode (data : Qubit, auxiliaryQubits : Qubit[]) : Unit
// Since decoding is the adjoint of encoding, we must
// denote that this operation supports the Adjoint
// functor.
@@ -83,7 +85,7 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
// each pair of qubits is positive (corresponding to the Zero) Result,
// such that we can learn syndrome information without revealing
// the state of an encoded qubit.
-
+
/// # Summary
/// This operation encodes into a bit-flip code, and confirms that
/// the parity measurements Z₀Z₁ and Z₁Z₂ both return positive eigenvalues
@@ -95,27 +97,27 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
/// if run on a target machine which supports assertions, and thus
/// can be used as a unit test of error-correction functionality.
operation CheckBitFlipCodeStateParity () : Unit {
-
+
// We start by preparing R_x(π / 3) |0〉 as our
// test state, along with two auxiliary qubits in the |00〉
// state that we can use to encode.
using ((data, auxiliaryQubits) = (Qubit(), Qubit[2])) {
let register = [data] + auxiliaryQubits;
Rx(PI() / 3.0, data);
-
+
// Next, we encode our test state.
EncodeIntoBitFlipCode(data, auxiliaryQubits);
-
+
// At this point, register represents a code block
// that protects the state R_x(π / 3) |0〉.
// We should thus be able to measure Z₀Z₁ and Z₁Z₂
// without disturbing the code state.
// To check this, we proceed in two steps:
-
+
// • Use Assert to ensure that the measurement
// will return Zero.
// • Use M to actually perform the measurement.
-
+
// If our target machine is a simulator, the first step
// will cause our quantum program to crash if the assertion
// fails. Since an assertion is not a physical operation,
@@ -125,13 +127,13 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
// further effect.
Assert([PauliZ, PauliZ, PauliI], register, Zero, "Z₀Z₁ was One!");
Assert([PauliI, PauliZ, PauliZ], register, Zero, "Z₁Z₂ was One!");
-
+
// The second step then actually performs the measurement,
// showing that we can make parity measurements without
// disturbing the state that we care about.
let parity01 = Measure([PauliZ, PauliZ, PauliI], register);
let parity12 = Measure([PauliI, PauliZ, PauliZ], register);
-
+
// To check that we have not disturbed the state, we decode,
// rotate back, and assert once more.
Adjoint EncodeIntoBitFlipCode(data, auxiliaryQubits);
@@ -139,22 +141,22 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
Assert([PauliZ], [data], Zero, "Didn't return to |0〉!");
}
}
-
-
+
+
// Now that we're assured we can measure Z₀Z₁ and Z₁Z₂ without disturbing
// the state of interest, let's use that to actually extract a syndrome
// and recover from a bit-flip error.
-
+
// Starting with the previous operation as a template, we'll remove
// the assertions for the parity checks and allow for an error operation
// to be passed as an input, then will modify it to use `parity01` and
// `parity12` to perform the correction.
-
+
// To take an error operation as an argument, we declare an input
// of type (Qubit[] => ()), representing something that can happen
// to an array of qubits. That is, we take the error to be applied
// in a black-box sense.
-
+
/// # Summary
/// This operation encodes into a bit-flip code, and confirms that
/// it can correct a given error applied to the logical state
@@ -172,31 +174,31 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
operation CheckBitFlipCodeCorrectsError(error : (Qubit[] => Unit)) : Unit {
using ((data, auxiliaryQubits) = (Qubit(), Qubit[2])) {
let register = [data] + auxiliaryQubits;
-
+
// We start by proceeding the same way as above
// in order to obtain the code block state |̅ψ〉.
Rx(PI() / 3.0, data);
EncodeIntoBitFlipCode(data, auxiliaryQubits);
-
+
// Next, we apply the error that we've been given to the
// entire register.
error(register);
-
+
// We measure the two parities Z₀Z₁ and Z₁z₂ as before
// to obtain our syndrome.
let parity01 = Measure([PauliZ, PauliZ, PauliI], register);
let parity12 = Measure([PauliI, PauliZ, PauliZ], register);
-
+
// To use the syndrome obtained above, we recall the table
// from :
-
+
// Error | Z₀Z₁ | Z₁Z₂
// ===================
// 1 | Zero | Zero
// X₀ | One | Zero
// X₁ | One | One
// X₂ | Zero | One
-
+
// Since the recovery is a classical inference procedure, we
// can represent it here by using if/elif statements:
if (parity01 == One and parity12 == Zero) {
@@ -208,7 +210,7 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
elif (parity01 == Zero and parity12 == One) {
X(register[2]);
}
-
+
// To check that we have not disturbed the state, we decode,
// rotate back, and assert once more.
Adjoint EncodeIntoBitFlipCode(data, auxiliaryQubits);
@@ -216,34 +218,34 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
Assert([PauliZ], [data], Zero, "Didn't return to |0〉!");
}
}
-
-
+
+
// Now that we have defined an operation which fails if the bit-flip
// code fails to protect a state from a given error, we can call it
// with the specific errors that the bit-flip code can correct.
// To do so, it is helpful to use the ApplyPauli operation from
// the canon, which takes an array of Pauli values and applies the
// corresponding sequence of operation.
-
+
// For example,
-
+
// ApplyPauli([PauliX, PauliY, PauliZ, PauliI], register);
-
+
// is equivalent to
-
+
// X(register[0]);
// Y(register[1]);
// Z(register[2]);
-
+
// If we partially apply ApplyPauli, we get an operation that
// represents applying a specific multi-qubit Pauli operator.
// For instance,
-
+
// ApplyPauli([PauliX, PauliI, PauliI], _)
-
+
// is an operation of type (Qubit[] => ()) that represents
// the X₀ bit-flip error.
-
+
/// # Summary
/// For each single-qubit bit-flip error on three qubits, this operation
/// encodes R_x(π / 3) |0〉 into the bit-flip code and asserts that the
@@ -259,15 +261,15 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
let X0 = ApplyPauli([PauliX, PauliI, PauliI], _);
let X1 = ApplyPauli([PauliI, PauliX, PauliI], _);
let X2 = ApplyPauli([PauliI, PauliI, PauliX], _);
-
+
// For each of these errors, we can then check
// that the bit flip code corrects them appropriately.
CheckBitFlipCodeCorrectsError(X0);
CheckBitFlipCodeCorrectsError(X1);
CheckBitFlipCodeCorrectsError(X2);
}
-
-
+
+
// Finally, we show how the logic described in this sample can be
// generalized by using functionality from the canon. This will allow
// us to consider much more involved error-correcting codes using the
@@ -275,13 +277,13 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
// To underscore this point, we write our new operation to take a QECC
// value as its input, where QECC is a type provided by the canon to
// collect all of the relevant information about an error-correcting code.
-
+
// The canon separates the role of the classical recovery process from
// the rest of an error-correcting code, allowing for recovery functions
// which use prior information about error models to improve code
// performance. Thus, we take a separate input of type RecoveryFn, a
// canon type used to denote functions which fulfill this role.
-
+
/// # Summary
/// This operation encodes into an arbitrary code, and confirms that
/// it can correct a given error applied to the logical state
@@ -297,7 +299,7 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
/// if run on a target machine which supports assertions, and thus
/// can be used as a unit test of error-correction functionality.
operation CheckCodeCorrectsError(code : QECC, nScratch : Int, fn : RecoveryFn, error : (Qubit[] => Unit)) : Unit {
-
+
// We once again begin by allocating some qubits to use as data
// and auxiliary qubits, and by preparing a test state on the
// data qubit.
@@ -307,14 +309,14 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
let register = [data] + auxiliaryQubits;
Rx(PI() / 3.0, data);
-
+
// We differ this time, however, in how we perform the
// encoding. The code input provided to this operation
// specifies an encoder, a decoder, and a syndrome
// measurement. Deconstructing that tuple will give us access
// to all three operations.
let (encode, decode, syndMeas) = code!;
-
+
// We can now encode as usual, with the slight exception
// that the encoder returns a value of a new user-defined type
// that marks the register as encoding a state.
@@ -324,31 +326,31 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
// Note that we also pass data as an array of qubits, to
// allow for codes which protect multiple qubits in one block.
let codeBlock = encode!([data], auxiliaryQubits);
-
+
// Next, we cause an error as usual.
error(codeBlock!);
-
+
// We can then ask the canon to perform the recovery, using
// our classical recovery procedure along with the code of
// interest.
Recover(code, fn, codeBlock);
-
+
// Having recovered, we can decode to obtain new qubit arrays
// pointing to the decoded data and auxiliary qubits.
- let (decodedData, decodedauxiliary) = decode!(codeBlock);
-
+ let (decodedData, decodedAuxiliary) = decode!(codeBlock);
+
// Finally, we test that our test state was protected.
Adjoint Rx(PI() / 3.0, data);
Assert([PauliZ], [data], Zero, "Didn't return to |0〉!");
}
}
-
-
+
+
// We will now write one last test that calls the new operation with
// the BitFlipCode and BitFlipRecoveryFn provided by the canon.
// Try replacing these with calls to other codes provided by the
// canon!
-
+
/// # Summary
/// For each single-qubit bit-flip error on three qubits, this operation
/// encodes R_x(π / 3) |0〉 into the bit-flip code and asserts that the
@@ -358,20 +360,18 @@ namespace Microsoft.Quantum.Samples.BitFlipCode {
/// This operation will fail when error correction fails
/// if run on a target machine which supports assertions, and thus
/// can be used as a unit test of error-correction functionality.
- operation CheckCanonBitFlipCodeCorrectsBitFlipErrors () : Unit {
+ operation CheckCanonBitFlipCodeCorrectsBitFlipErrors() : Unit {
let code = BitFlipCode();
let recoveryFn = BitFlipRecoveryFn();
let X0 = ApplyPauli([PauliX, PauliI, PauliI], _);
let X1 = ApplyPauli([PauliI, PauliX, PauliI], _);
let X2 = ApplyPauli([PauliI, PauliI, PauliX], _);
-
+
// For each of these errors, we can then check
// that the bit flip code corrects them appropriately.
- let check = CheckCodeCorrectsError(code, 2, recoveryFn, _);
- let errors = [X0, X1, X2];
- check(errors[0]);
- check(errors[1]);
- check(errors[2]);
+ for (error in [X0, X1, X2]) {
+ CheckCodeCorrectsError(code, 2, recoveryFn, error);
+ }
}
-
+
}
diff --git a/samples/error-correction/bit-flip-code/Driver.cs b/samples/error-correction/bit-flip-code/Host.cs
similarity index 96%
rename from samples/error-correction/bit-flip-code/Driver.cs
rename to samples/error-correction/bit-flip-code/Host.cs
index e24241e6e7bd..dc849adc0841 100644
--- a/samples/error-correction/bit-flip-code/Driver.cs
+++ b/samples/error-correction/bit-flip-code/Host.cs
@@ -23,7 +23,7 @@ static void Main(string[] args)
// We begin by defining a quantum simulator to be our target
// machine.
- var sim = new QuantumSimulator(throwOnReleasingQubitsNotInZeroState: true);
+ using var sim = new QuantumSimulator(throwOnReleasingQubitsNotInZeroState: true);
#endregion
diff --git a/samples/error-correction/bit-flip-code/README.md b/samples/error-correction/bit-flip-code/README.md
index 23198224e1a9..445fe427bb98 100644
--- a/samples/error-correction/bit-flip-code/README.md
+++ b/samples/error-correction/bit-flip-code/README.md
@@ -1,14 +1,58 @@
-# Bit-flip Quantum Code Sample #
+---
+page_type: sample
+languages:
+- qsharp
+- python
+- csharp
+products:
+- qdk
+description: "This sample uses the Q# standard libraries to implement a three-qubit bit-flip quantum error correction code."
+urlFragment: bit-flip-code
+---
-This sample describes a simple quantum code that encodes 1 qubit into 3 qubits and protects against a single bit-flip error.
-## Running the Sample ##
+# Bit-flip Quantum Code Sample
-Open the `QsharpSamples.sln` solution in Visual Studio and set the .csproj file in the manifest as the startup project.
+This sample demonstrates:
+
+- Using the Q# standard libraries to implement a simple quantum error correction code.
+
+## Prerequisites
+
+- The Microsoft [Quantum Development Kit](https://docs.microsoft.com/quantum/install-guide/).
+
+## Running the Sample
+
+This sample can be run in a number of different ways, depending on your preferred environment.
+
+### Python in Visual Studio Code or the Command Line
+
+At a terminal, run the following command:
+
+```bash
+python host.py
+```
+
+### C# in Visual Studio Code or the Command Line
+
+At a terminal, run the following command:
+
+```dotnetcli
+dotnet run
+```
+
+### C# in Visual Studio 2019
+
+Open the folder containing this sample in Visual Studio ("Open a local folder" from the Getting Started screen or "File → Open → Folder..." from the menu bar) and set `BitFlipCode.csproj` as the startup project.
Press Start in Visual Studio to run the sample.
-## Manifest ##
+## Manifest
+
+- [BitFlipCode.qs](https://github.com/microsoft/Quantum/blob/master/samples/error-correction/bit-flip-code/BitFlipCode.qs): Q# code implementing quantum operations for this sample.
+- [Host.cs](https://github.com/microsoft/Quantum/blob/master/samples/error-correction/bit-flip-code/Host.cs): C# code to interact with and print out results of the Q# operations for this sample.
+- [host.py](https://github.com/microsoft/Quantum/blob/master/samples/error-correction/bit-flip-code/host.py): Python host program to call into the Q# sample.
+- [BitFlipCode.csproj](https://github.com/microsoft/Quantum/blob/master/samples/error-correction/bit-flip-code/BitFlipCode.csproj): Main C# project for the sample.
+
+## Further resources
-- [BitFlipCode.qs](./BitFlipCode.qs): Q# code implementing quantum operations for this sample.
-- [Driver.cs](./Driver.cs): C# code to interact with and print out results of the Q# operations for this sample.
-- [BitFlipCode.csproj](./BitFlipCode.csproj): Main C# project for the sample.
+- [Error correction library concepts](https://docs.microsoft.com/quantum/libraries/standard/error-correction)