diff --git a/samples/algorithms/chsh-game/CHSHGame.csproj b/samples/algorithms/chsh-game/CHSHGame.csproj index 007bd60caaf5..e8f657199fba 100644 --- a/samples/algorithms/chsh-game/CHSHGame.csproj +++ b/samples/algorithms/chsh-game/CHSHGame.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/algorithms/database-search/DatabaseSearchSample.csproj b/samples/algorithms/database-search/DatabaseSearchSample.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/algorithms/database-search/DatabaseSearchSample.csproj +++ b/samples/algorithms/database-search/DatabaseSearchSample.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/algorithms/integer-factorization/IntegerFactorization.csproj b/samples/algorithms/integer-factorization/IntegerFactorization.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/algorithms/integer-factorization/IntegerFactorization.csproj +++ b/samples/algorithms/integer-factorization/IntegerFactorization.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/algorithms/oracle-synthesis/OracleSynthesis.csproj b/samples/algorithms/oracle-synthesis/OracleSynthesis.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/algorithms/oracle-synthesis/OracleSynthesis.csproj +++ b/samples/algorithms/oracle-synthesis/OracleSynthesis.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/algorithms/order-finding/OrderFinding.csproj b/samples/algorithms/order-finding/OrderFinding.csproj index 59c727c5ed0b..e1b9cd037ca0 100644 --- a/samples/algorithms/order-finding/OrderFinding.csproj +++ b/samples/algorithms/order-finding/OrderFinding.csproj @@ -1,4 +1,4 @@ - + Exe netcoreapp3.1 diff --git a/samples/algorithms/repeat-until-success/README.md b/samples/algorithms/repeat-until-success/README.md new file mode 100644 index 000000000000..b31bbe597b61 --- /dev/null +++ b/samples/algorithms/repeat-until-success/README.md @@ -0,0 +1,55 @@ +--- +page_type: sample +languages: +- qsharp +products: +- qdk +description: "Using repeat-until-success patterns in quantum programs" +--- + +# Repeat-until-success + +This is an example of a Repeat-Until-Success (RUS) algorithm implemented in a Q# program. +The algorithm has been described in [Adam Paetznick, Krysta M. Svore, Quantum Information & Computation 14(15 & 16): 1277-1301 (2014)](https://arxiv.org/abs/1311.1074). + +## Prerequisites ## + +- The Microsoft [Quantum Development Kit](https://docs.microsoft.com/quantum/install-guide/). +## Description + +The idea for the RUS algorithm originates from the goal of decomposing a single-qubit unitary operation into a sequence of gates from a given universal basis set. In general, the goal of a RUS algorithm is to reduce the number of Clifford gates needed to execute said unitary operation by using one or more auxiliary qubits that are measured during the execution of the algorithm to indicate whether the desired output state has been achieved. This specific RUS algorithm consists of a circuit that uses two auxiliary qubits, which we label `auxiliary` and `resource`, and one `target` qubit. + +In this example, the RUS algorithm aims to apply exp(i⋅ArcTan(2)⋅Z) or a 𝑉₃-gate on the `target` qubit. The algorithm is based on the logic mapped out in the below circuit diagram (Fig. 1(c) from [source](https://arxiv.org/abs/1311.1074)). The qubits on the left hand side are labeled from top to bottom: `auxiliary`, `resource` and `target`. As described in the whitepaper, the desired operation will have been achieved when the measurements on both `auxiliary` and `resource` qubits returns `Zero`. When that happens we can exit the program and return the result. In all other cases, we would have to re-run the circuit. Important to note is that if the auxiliary qubit returns `Zero` but the `resource` qubit returns `One`, the resulting operation will have been an effective `Z` rotation which we will then need to correct for. + +![RUS circuit diagram](RUS.png) + +Since both the `auxiliary` and `resource` qubits need to return `Zero`, we can split this circuit into two parts, in the diagram circled in red and blue. If we execute the first part and it returns `One`, we can skip running the second part and start over. Since the first part doesn't perform any operations on the `target` qubit, we don't have to make any corrections on the `target` qubit and just reinitialize the `auxiliary` and `resource` qubit. + +If we measure `Zero` on the `auxiliary` qubit, we run the second part and measure the `resource` qubit. If the measurement returns `Zero`, we measure the `target` qubit and exit the program successfully. If the measurement returns `One`, we need to apply an `Adjoint Z` operation on the `target` qubit as mentioned above. + +The program returns a tuple with three values: whether the program ran successfully, the measurement result on the `target` qubit and the number of iterations that was run to obtain the result. + +## Running the Sample + +Browse to the `samples/algorithms/repeat-until-success` folder and run `dotnet build` to build the project. Then run `dotnet run [options] --no-build`. Optionally, omit the `--no-build` option to automatically build the project before execution. + +To see options, run `dotnet run -- --help`. +``` +Options: + --input-value (REQUIRED) Boolean value for input qubit (true maps to One, false maps to Zero) + --input-basis (REQUIRED) Pauli basis to prepare input qubit in + --limit (REQUIRED) Integer limit to number of repeats of circuit +``` + +## Manifest + +- **repeat-until-success/** + - [RepeatUntilSuccess.csproj](./RepeatUntilSuccess.csproj): Main C# project for the example. + - [RepeatUntilSuccess.qs](./RepeatUntilSuccess.qs): The Q# implementation of the RUS algorithm. + +## Example run + +``` +> dotnet run --input-value true --input-basis PauliZ --limit 10 +(True, One, 3) +``` diff --git a/samples/algorithms/repeat-until-success/RUS.png b/samples/algorithms/repeat-until-success/RUS.png new file mode 100644 index 000000000000..bd37801a663d Binary files /dev/null and b/samples/algorithms/repeat-until-success/RUS.png differ diff --git a/samples/algorithms/repeat-until-success/RepeatUntilSuccess.csproj b/samples/algorithms/repeat-until-success/RepeatUntilSuccess.csproj new file mode 100644 index 000000000000..3172cb0ebd9e --- /dev/null +++ b/samples/algorithms/repeat-until-success/RepeatUntilSuccess.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.1 + + + diff --git a/samples/algorithms/repeat-until-success/RepeatUntilSuccess.qs b/samples/algorithms/repeat-until-success/RepeatUntilSuccess.qs new file mode 100644 index 000000000000..6021662ebfc4 --- /dev/null +++ b/samples/algorithms/repeat-until-success/RepeatUntilSuccess.qs @@ -0,0 +1,222 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Samples.RepeatUntilSuccess { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Preparation; + open Microsoft.Quantum.Diagnostics; + + /// # Summary + /// Example of a Repeat-until-success algorithm implementing a circuit + /// that achieves exp(i⋅ArcTan(2)⋅Z) by Paetznick & Svore. + /// The exp(𝑖 ArcTan(2) 𝑍) operation is also known as the "𝑉 gate." + /// # References + /// - [ *Adam Paetznick, Krysta M. Svore*, + /// Quantum Information & Computation 14(15 & 16): 1277-1301 (2014) + /// ](https://arxiv.org/abs/1311.1074) + /// For circuit diagram, see file RUS.png. + /// + /// # Input + /// ## inputBasis + /// Pauli basis in which to prepare input qubit + /// ## inputValue + /// Boolean value for input qubit (true maps to One, false maps to Zero) + /// ## limit + /// Integer limit to number of repeats of circuit + /// + /// # Remarks + /// The program executes a circuit on a "target" qubit using an "auxiliary" + /// and "resource" qubit. The circuit consists of two parts (red and blue + /// in image). + /// The goal is to measure Zero for both the auxiliary and resource qubit. + /// If this succeeds, the program will have effectively applied an + /// Rz(arctan(2)) gate (also known as V_3 gate) on the target qubit. + /// If this fails, the program reruns the circuit up to times. + @EntryPoint() + operation CreateQubitsAndApplyRzArcTan2( + inputValue : Bool, + inputBasis : Pauli, + limit : Int + ) + : (Bool, Result, Int) { + using ((auxiliary, resource, target) = (Qubit(), Qubit(), Qubit())) { + // Initialize qubits to starting values (|+⟩, |+⟩, |0⟩/|1⟩) + InitializeQubits( + inputBasis, inputValue, auxiliary, resource, target + ); + let (success, numIter) = ApplyRzArcTan2( + inputBasis, inputValue, limit, auxiliary, resource, target); + let result = Measure([inputBasis], [target]); + // From version 0.12 it is no longer necessary to release qubits + /// in zero state. + ResetAll([target, resource, auxiliary]); + return (success, result, numIter); + } + } + + /// # Summary + /// Apply Rz(arctan(2)) on qubits using repeat until success algorithm. + /// + /// # Input + /// ## inputBasis + /// Pauli basis in which to prepare input qubit + /// ## inputValue + /// Boolean value for input qubit (true maps to One, false maps to Zero) + /// ## limit + /// Integer limit to number of repeats of circuit + /// ## auxiliary + /// Auxiliary qubit + /// ## resource + /// Resource qubit + /// ## target + /// Target qubit + /// + /// # Output + /// Tuple of (success, numIter) where success = false if the number of + /// iterations (numIter) exceeds the input + operation ApplyRzArcTan2( + inputBasis : Pauli, + inputValue : Bool, + limit : Int, + auxiliary : Qubit, + resource : Qubit, + target : Qubit + ) + : (Bool, Int) { + // Initialize results to One by default. + mutable done = false; + mutable success = false; + mutable numIter = 0; + + repeat { + // Assert valid starting states for all qubits + AssertMeasurement([PauliX], [auxiliary], Zero, + "Auxiliary qubit is not in |+⟩ state."); + AssertMeasurement([PauliX], [resource], Zero, + "Resource qubit is not in |+⟩ state."); + AssertQubitIsInState(target, inputBasis, inputValue); + + // Run Part 1 of the program. + let result1 = ApplyAndMeasurePart1(auxiliary, resource); + // We'll only run Part 2 if Part 1 returns Zero. + // Otherwise, we'll skip and rerun Part 1 again. + if (result1 == Zero) { //|0+⟩ + let result2 = ApplyAndMeasurePart2(resource, target); + if (result2 == Zero) { //|00⟩ + set success = true; + } else { //|01⟩ + Z(resource); // Reset resource from |-⟩ to |+⟩ + Adjoint Z(target); // Correct effective Z rotation on target + } + } else { //|1+⟩ + // Set auxiliary and resource qubit back to |+⟩ + Z(auxiliary); + Reset(resource); + H(resource); + } + set done = success or (numIter >= limit); + set numIter = numIter + 1; + } + until (done); + return (success, numIter); + } + + /// # Summary + /// Initialize axiliary and resource qubits in |+⟩, target in |0⟩ or |1⟩. + /// + /// # Input + /// ## inputBasis + /// Pauli basis in which to prepare input qubit + /// ## inputValue + /// Boolean value for input qubit (true maps to One, false maps to Zero) + /// ## limit + /// Integer limit to number of repeats of circuit + /// ## auxiliary + /// Auxiliary qubit + /// ## resource + /// Resource qubit + /// ## target + /// Target qubit + operation InitializeQubits( + inputBasis : Pauli, + inputValue : Bool, + auxiliary : Qubit, + resource : Qubit, + target : Qubit + ) + : Unit { + // Prepare auxiliary and resource qubits in |+⟩ state + H(auxiliary); + H(resource); + + // Prepare target qubit in |0⟩ or |1⟩ state, depending on input value + if (inputValue) { + X(target); + } + PrepareQubit(inputBasis, target); + } + + /// # Summary + /// Apply part 1 of RUS circuit (red circuit shown in README) and measure + /// auxiliary qubit in Pauli X basis + /// + /// # Input + /// ## auxiliary + /// Auxiliary qubit + /// ## resource + /// Resource qubit + operation ApplyAndMeasurePart1( + auxiliary : Qubit, + resource : Qubit + ) + : Result { + within { + T(auxiliary); + } apply { + CNOT(resource, auxiliary); + } + + return Measure([PauliX], [auxiliary]); + } + + /// # Summary + /// Apply part 2 of RUS circuit (blue circuit shown in README) and measure + /// resource qubit in Pauli X basis + /// + /// # Input + /// ## resource + /// Resource qubit + /// ## target + /// Target qubit + operation ApplyAndMeasurePart2(resource : Qubit, target : Qubit) : Result { + T(target); + Z(target); + CNOT(target, resource); + T(resource); + + return Measure([PauliX], [resource]); + } + + /// # Summary + /// Assert target qubit state is the desired input value in the desired + /// input basis. + /// + /// ## target + /// Target qubit + /// ## inputBasis + /// Pauli basis in which to prepare input qubit + /// ## inputValue + /// Boolean value for input qubit (true maps to One, false maps to Zero) + operation AssertQubitIsInState( + target : Qubit, + inputBasis : Pauli, + inputValue : Bool + ) + : Unit { + AssertMeasurement( + [inputBasis], [target], inputValue ? One | Zero, + $"Qubit is not in {inputValue ? One | Zero} state for given input basis." + ); + } +} diff --git a/samples/algorithms/reversible-logic-synthesis/ReversibleLogicSynthesis.csproj b/samples/algorithms/reversible-logic-synthesis/ReversibleLogicSynthesis.csproj index e1e065249b67..95fc64fb8b5a 100644 --- a/samples/algorithms/reversible-logic-synthesis/ReversibleLogicSynthesis.csproj +++ b/samples/algorithms/reversible-logic-synthesis/ReversibleLogicSynthesis.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/algorithms/simple-grover/SimpleGroverSample.csproj b/samples/algorithms/simple-grover/SimpleGroverSample.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/algorithms/simple-grover/SimpleGroverSample.csproj +++ b/samples/algorithms/simple-grover/SimpleGroverSample.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/characterization/phase-estimation/PhaseEstimationSample.csproj b/samples/characterization/phase-estimation/PhaseEstimationSample.csproj index 41cb4c97b6a5..879f59c1aeee 100644 --- a/samples/characterization/phase-estimation/PhaseEstimationSample.csproj +++ b/samples/characterization/phase-estimation/PhaseEstimationSample.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/error-correction/bit-flip-code/BitFlipCode.csproj b/samples/error-correction/bit-flip-code/BitFlipCode.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/error-correction/bit-flip-code/BitFlipCode.csproj +++ b/samples/error-correction/bit-flip-code/BitFlipCode.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/getting-started/measurement/Measurement.csproj b/samples/getting-started/measurement/Measurement.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/getting-started/measurement/Measurement.csproj +++ b/samples/getting-started/measurement/Measurement.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/getting-started/simple-algorithms/SimpleAlgorithms.csproj b/samples/getting-started/simple-algorithms/SimpleAlgorithms.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/getting-started/simple-algorithms/SimpleAlgorithms.csproj +++ b/samples/getting-started/simple-algorithms/SimpleAlgorithms.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/simulation/ising/adiabatic/AdiabaticIsingSample.csproj b/samples/simulation/ising/adiabatic/AdiabaticIsingSample.csproj index a2f770e54c82..026ace46e965 100644 --- a/samples/simulation/ising/adiabatic/AdiabaticIsingSample.csproj +++ b/samples/simulation/ising/adiabatic/AdiabaticIsingSample.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/simulation/ising/generators/IsingGeneratorsSample.csproj b/samples/simulation/ising/generators/IsingGeneratorsSample.csproj index 69ae5b1ee102..3172cb0ebd9e 100644 --- a/samples/simulation/ising/generators/IsingGeneratorsSample.csproj +++ b/samples/simulation/ising/generators/IsingGeneratorsSample.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/simulation/ising/phase-estimation/IsingPhaseEstimationSample.csproj b/samples/simulation/ising/phase-estimation/IsingPhaseEstimationSample.csproj index 2032efb5ef8b..ecc29e4f5a4b 100644 --- a/samples/simulation/ising/phase-estimation/IsingPhaseEstimationSample.csproj +++ b/samples/simulation/ising/phase-estimation/IsingPhaseEstimationSample.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/samples/tests/sample-tests/RepeatUntilSuccessTests.qs b/samples/tests/sample-tests/RepeatUntilSuccessTests.qs new file mode 100644 index 000000000000..e12b965a123c --- /dev/null +++ b/samples/tests/sample-tests/RepeatUntilSuccessTests.qs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Samples.RepeatUntilSuccess; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Math; + + @Test("QuantumSimulator") + operation RepeatUntilSuccessInitializeTest() : Unit { + let inputBasis = PauliX; + let inputValue = true; + using ((auxiliary, resource, target) = (Qubit(), Qubit(), Qubit())) { + // Initialize qubits to starting values (|+⟩, |+⟩, |0⟩/|1⟩) + InitializeQubits(inputBasis, inputValue, auxiliary, resource, target); + + // Assert valid starting states for all qubits + AssertMeasurement([PauliX], [auxiliary], Zero, "Auxiliary qubit is not in |+⟩ state."); + AssertMeasurement([PauliX], [resource], Zero, "Resource qubit is not in |+⟩ state."); + AssertQubitIsInState(target, inputBasis, inputValue); + + // Reset qubits (should no longer be necessary in v0.12) + Reset(auxiliary); + Reset(resource); + Reset(target); + } + } + + @Test("QuantumSimulator") + operation RepeatUntilSuccessRzArcTan2Test() : Unit { + let inputBasis = PauliX; + let inputValue = true; + let limit = 50; // typically executes succesfully in n < 10 so 50 is playing it safe + using ((auxiliary, resource, target) = (Qubit(), Qubit(), Qubit())) { + // Initialize qubits to starting values (|+⟩, |+⟩, |0⟩/|1⟩) + InitializeQubits(inputBasis, inputValue, auxiliary, resource, target); + AssertMeasurement([inputBasis], [target], One, "Target qubit is not in |1⟩ state."); + let (success, numIter) = ApplyRzArcTan2(inputBasis, inputValue, limit, auxiliary, resource, target); + Rz(2.0 * ArcTan(2.0), target); // Rotate back to initial state + + if (success == true) { + AssertMeasurement([PauliX], [auxiliary], Zero, "Auxiliary qubit is not in |-⟩ state."); + AssertMeasurement([PauliX], [resource], Zero, "Resource qubit is not in |-⟩ state."); + AssertMeasurement([inputBasis], [target], One, "Target qubit is not in 1 state for the given basis."); + } + + // Reset qubits (should no longer be necessary in v0.12) + Reset(auxiliary); + Reset(resource); + Reset(target); + + } + } +} diff --git a/samples/tests/sample-tests/SampleTests.csproj b/samples/tests/sample-tests/SampleTests.csproj index 4a84660c9718..362560e440a0 100644 --- a/samples/tests/sample-tests/SampleTests.csproj +++ b/samples/tests/sample-tests/SampleTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 x64 @@ -19,10 +19,12 @@ + - + +