diff --git a/samples/error-correction/README.md b/samples/error-correction/README.md index 6d1fe80436b0..1c78ac476ef7 100644 --- a/samples/error-correction/README.md +++ b/samples/error-correction/README.md @@ -4,4 +4,6 @@ These samples show how to work with quantum error correcting codes in Q# program - **[Bit-flip Code](./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. - \ No newline at end of file + +- **[Syndrome](./syndrome)**: + This sample implements a simple syndrome that can be used to detect errors in quantum algorithms executed on quantum hardware. diff --git a/samples/error-correction/syndrome/README.md b/samples/error-correction/syndrome/README.md new file mode 100644 index 000000000000..fcb709c6b777 --- /dev/null +++ b/samples/error-correction/syndrome/README.md @@ -0,0 +1,40 @@ +--- +page_type: sample +languages: +- qsharp +- python +products: +- qdk +description: "This sample uses the Q# standard libraries to implement a syndrome for detecting errors in a given number of data qubits." +urlFragment: quantum-syndrome +--- + + +# Measuring quantum error syndromes with Q\# + +This sample demonstrates how to create a partially implemented Syndrome for detecting errors generated in noisy hardware. The sample shows how this is implemented using Q# standard libraries. Currently, it does not simulate realistic noise so the resulting unitary operator is trivial. However, the program is useful to demonstrate the concept of a syndrome. + +The algorithm used is described in [Surface codes: Towards practical large-scale quantum computation](https://arxiv.org/abs/1208.0928) by Fowler et al. In particular, this example implements the circuit shown in Figure 1 c. in this paper. + +The circuit uses _N data qubits_, where _N_ is a number given as input to the script, plus one _auxiliary_ qubit. The principle of the circuit is as follows. First, we prepare our data qubits in random states of a set of random bases, in order to simulate a noisy process. The circuit then propagates these errors to the auxiliary qubit using the principle of _phase kickback_. Phase kickback works by encoding pieces of a quantum algorithm into the global phase of an extra (auxiliary) qubit. + +We start by preparing an auxiliary qubit into the superposition state by applying a `H` operation, to change to the _X_ computational basis. Subsequently, we apply controlled Pauli operators to each of the data qubits in random order, using the auxiliary qubit as control. The goal is to create a global phase shift on the auxiliary qubit, that will depend on the state of the data qubits. After the circuit runs, the auxiliary qubit is measured in the _X_-basis, which reveals its phase information. + +## Prerequisites + +- The Microsoft [Quantum Development Kit](https://docs.microsoft.com/quantum/install-guide/). + +## Running the Sample + +To run the sample, run `python syndrome.py --qubits `, where `` is replaced by the number of qubits. For more information, run `python syndrome.py --help`. + +## Manifest + +- [Syndrome.qs](https://github.com/microsoft/Quantum/blob/master/samples/error-correction/syndrome/Syndrome.qs): Q# code implementing quantum operations for this sample. +- [syndrome.py](https://github.com/microsoft/Quantum/blob/master/samples/error-correction/syndrome/syndrome.py): Python script to interact with and print out results of the Q# operations for this sample for a given number of data qubits. Example usage: `python syndrome.py --qubits 5`. +- [Syndrome.csproj](https://github.com/microsoft/Quantum/blob/master/samples/error-correction/syndrome/Syndrome.csproj): Main Q# project for the sample. + +## Further resources + +- [Error correction library concepts](https://docs.microsoft.com/quantum/libraries/standard/error-correction) +- [Pauli measurements](https://docs.microsoft.com/en-us/quantum/concepts/pauli-measurements) diff --git a/samples/error-correction/syndrome/Syndrome.csproj b/samples/error-correction/syndrome/Syndrome.csproj new file mode 100644 index 000000000000..cffd30f1fd06 --- /dev/null +++ b/samples/error-correction/syndrome/Syndrome.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.1 + + + diff --git a/samples/error-correction/syndrome/Syndrome.qs b/samples/error-correction/syndrome/Syndrome.qs new file mode 100644 index 000000000000..1d80005989c2 --- /dev/null +++ b/samples/error-correction/syndrome/Syndrome.qs @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Samples.ErrorCorrection.Syndrome { + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Preparation; + open Microsoft.Quantum.Measurement; + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Convert; + + /// # Summary + /// Measure qubit in a given basis and return the result + /// + /// # Input + /// ## basis + /// Pauli basis in which to perform measurement + /// ## qubit + /// Qubit to measure + /// + /// # Output + /// ## result + /// Measurement result + operation BasisMeasure(basis : Pauli, qubit : Qubit): Result { + let result = Measure([basis], [qubit]); + return result; + } + + /// # Summary + /// Prepare qubit in a given basis. Optionally flip the qubit if the value + /// is True (One). + /// + /// # Input + /// ## basis + /// Basis to prepare the qubit in + /// ## qubit + /// Qubit to prepare + /// ## value + /// Value to prepare the qubit in (True for One, False for Zero) + operation PrepareInBasis(basis : Pauli, qubit : Qubit, value : Bool): Unit { + if (value) { + X(qubit); + } + PrepareQubit(basis, qubit); + } + + /// # Summary + /// Creates a Pseudo Syndrome by using an auxiliary qubit. + /// This algorithm relies on several controlled Pauli operations. When + /// there is no error introduced after state preparation, the circuit is + /// trivial and no change is measured on the auxiliary qubit. However, if + /// there are miscellaneous rotations on the data qubits due to noise, due + /// to phase kickback the auxiliary qubit will gain a small phase shift. + /// By measuring the auxiliary qubit in the X basis we then project that + /// phase difference onto the measurement basis. + /// + /// # Input + /// ## inputValues + /// Array of Boolean input values for data qubits. + /// ## encodingBases + /// Array of Pauli bases to encode errors in for controlled Pauli operations on. + /// The length of this array needs to be the same as + /// inputValues. + /// ## qubitIndices + /// List of qubit indices on which to apply controlled Pauli operators. + /// This determines the order in which the controlled Pauli's are applied. + /// The length of this array needs to be the same as inputValues. + /// + /// # Output + /// ## (auxiliaryResult, dataResult) + /// Tuple of the measurement results of the auxiliary qubit and data qubits. + operation SamplePseudoSyndrome ( + inputValues : Bool[], + encodingBases : Pauli[], + qubitIndices : Int[] + ): ( Result, Result[] ) { + // Check that input lists are of equal length + if ((Length(inputValues) != Length(encodingBases)) + or (Length(inputValues) != Length(qubitIndices))) { + fail $"Lengths of input values, encoding bases and qubitIndices must be + equal. Found lengths: + {Length(inputValues)}, {Length(encodingBases)}, {Length(qubitIndices)}"; + } + + using ((block, auxiliary) = (Qubit[Length(inputValues)], Qubit())) { + for ((qubit, value, basis) in Zip3(block, inputValues, encodingBases)) { + PrepareInBasis(basis, qubit, value); + } + H(auxiliary); + // Apply Controlled Pauli operations to data qubits, resulting in a phase kickback + /// on the auxiliary qubit + for ((index, basis) in Zip(qubitIndices, encodingBases)) { + Controlled ApplyPauli([auxiliary], ([basis], [block[index]])); + } + let auxiliaryResult = Measure([PauliX], [auxiliary]); + let dataResult = ForEach(BasisMeasure, Zip(encodingBases, block)); + // Reset qubits - optional, only for QDK version < 0.12 + ResetAll(block); + Reset(auxiliary); + return ( auxiliaryResult, dataResult ); + } + } +} diff --git a/samples/error-correction/syndrome/syndrome.py b/samples/error-correction/syndrome/syndrome.py new file mode 100644 index 000000000000..621c4c3763e2 --- /dev/null +++ b/samples/error-correction/syndrome/syndrome.py @@ -0,0 +1,43 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +""" +Script for running Pseudo-syndrome example as defined in Syndrome.qs. +This script takes the number of data qubits as input. + +Example usage: + python syndrome.py -q 5 +""" + +import numpy as np +import qsharp +import argparse + +from Microsoft.Quantum.Samples.ErrorCorrection.Syndrome import SamplePseudoSyndrome + +parser = argparse.ArgumentParser( + prog="PseudoSyndrome", + description="Program for running a PseudoSyndrome circuit that detects \ + random errors on qubits in gate sequence." +) +parser.add_argument("-q", "--qubits", type=int, default=1) + +if __name__ == "__main__": + args = parser.parse_args() + # To be refactored to qsharp.Pauli + # (See IQSharp ticket https://github.com/microsoft/iqsharp/issues/256) + paulis = ["PauliX", "PauliY", "PauliZ"] + qubit_indices = list(range(args.qubits)) + np.random.shuffle(qubit_indices) + input_values = [np.random.rand() > .5 for n in range(args.qubits)] + encoding_bases = [np.random.choice(paulis) for n in range(args.qubits)] + result = SamplePseudoSyndrome.simulate( + inputValues=input_values, + encodingBases=encoding_bases, + qubitIndices=qubit_indices) + auxiliary, data = result + + print(f"Inputs: {[int(val) for val in input_values]}\ + \nBases: {encoding_bases}\ + \nQubit indices: {qubit_indices}") + print(f"Auxiliary: {auxiliary}") + print(f"Data qubits: {data}")