Migrate the katas to QDK 0.3 and .NET Core 2.1 (#43)

This commit is contained in:
Mariia Mykhailova 2018-10-30 08:48:56 -07:00 коммит произвёл GitHub
Родитель 5486ea21ba
Коммит 63e4e52a48
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
40 изменённых файлов: 3935 добавлений и 4366 удалений

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.BasicGates</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,37 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.BasicGates
{
namespace Quantum.Kata.BasicGates {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Part I. Single-Qubit Gates
//////////////////////////////////////////////////////////////////
// Task 1.1. State flip
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the state of the qubit to α |1⟩ + β |0⟩.
// Example:
// If the qubit is in state |0⟩, change its state to |1⟩.
// If the qubit is in state |1⟩, change its state to |0⟩.
operation StateFlip_Reference (q : Qubit) : ()
{
body
{
// Example:
// If the qubit is in state |0⟩, change its state to |1⟩.
// If the qubit is in state |1⟩, change its state to |0⟩.
operation StateFlip_Reference (q : Qubit) : Unit {
body (...) {
X(q);
}
adjoint self;
}
// Task 1.2. Basis change: |0⟩ to |+⟩ and |1⟩ to |-⟩ (and vice versa)
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the state of the qubit as follows:
@ -39,195 +41,206 @@ namespace Quantum.Kata.BasicGates
// If the qubit is in state |1⟩, change its state to |-⟩ = (|0⟩ - |1⟩) / sqrt(2).
// If the qubit is in superposition, change its state according to the effect on basis vectors.
// Note: |+⟩ and |-⟩ form a different basis for single-qubit states, called X basis.
operation BasisChange_Reference (q : Qubit) : ()
{
body
{
operation BasisChange_Reference (q : Qubit) : Unit {
body (...) {
H(q);
}
adjoint self;
}
// Task 1.3. Sign flip: |+⟩ to |-⟩ and vice versa.
// Inputs: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the qubit state to α |0⟩ - β |1⟩ (flip the sign of |1⟩ component of the superposition).
operation SignFlip_Reference (q : Qubit) : ()
{
body
{
operation SignFlip_Reference (q : Qubit) : Unit {
body (...) {
Z(q);
}
adjoint self;
}
// Task 1.4*. Amplitude change (|0⟩ to cos(alpha)*|0⟩ + sin(alpha)*|1⟩).
// Inputs:
// Inputs:
// 1) A qubit in state β|0⟩ + γ|1⟩.
// 2) Angle alpha, in radians, represented as Double
// Goal: Change the state of the qubit as follows:
// If the qubit is in state |0⟩, change its state to cos(alpha)*|0⟩ + sin(alpha)*|1⟩.
// If the qubit is in state |1⟩, change its state to -sin(alpha)*|0⟩ + cos(alpha)*|1⟩.
// If the qubit is in superposition, change its state according to the effect on basis vectors.
operation AmplitudeChange_Reference (q : Qubit, alpha : Double) : ()
{
body
{
operation AmplitudeChange_Reference (q : Qubit, alpha : Double) : Unit {
body (...) {
Ry(2.0 * alpha, q);
}
adjoint auto;
adjoint invert;
}
// Task 1.5. Phase flip
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the qubit state to α |0⟩ + iβ |1⟩ (flip the phase of |1⟩ component of the superposition).
operation PhaseFlip_Reference (q : Qubit) : ()
{
body
{
operation PhaseFlip_Reference (q : Qubit) : Unit {
body (...) {
S(q);
// alternatively Rz(0.5 * PI(), q);
}
adjoint auto;
adjoint invert;
}
// Task 1.6*. Phase change
// Inputs:
// Inputs:
// 1) A qubit in state β|0⟩ + γ|1⟩.
// 2) Angle alpha, in radians, represented as Double
// Goal: Change the state of the qubit as follows:
// If the qubit is in state |0⟩, don't change its state.
// If the qubit is in state |1⟩, change its state to exp(i*alpha)|1⟩.
// If the qubit is in superposition, change its state according to the effect on basis vectors.
operation PhaseChange_Reference (q : Qubit, alpha : Double) : ()
{
body
{
operation PhaseChange_Reference (q : Qubit, alpha : Double) : Unit {
body (...) {
Rz(alpha, q);
}
adjoint auto;
adjoint invert;
}
// Task 1.7. Bell state change - 1
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// Goal: Change the two-qubit state to |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2).
operation BellStateChange1_Reference (qs : Qubit[]) : ()
{
body
{
operation BellStateChange1_Reference (qs : Qubit[]) : Unit {
body (...) {
Z(qs[0]);
// alternatively Z(qs[1]);
}
adjoint auto;
adjoint invert;
}
// Task 1.8. Bell state change - 2
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// Goal: Change the two-qubit state to |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2).
operation BellStateChange2_Reference (qs : Qubit[]) : ()
{
body
{
operation BellStateChange2_Reference (qs : Qubit[]) : Unit {
body (...) {
X(qs[0]);
// alternatively X(qs[1]);
}
adjoint auto;
adjoint invert;
}
// Task 1.9. Bell state change - 3
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// Goal: Change the two-qubit state to |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2).
operation BellStateChange3_Reference (qs : Qubit[]) : ()
{
body
{
operation BellStateChange3_Reference (qs : Qubit[]) : Unit {
body (...) {
Y(qs[0]);
}
adjoint auto;
adjoint invert;
}
//////////////////////////////////////////////////////////////////
// Part II. Multi-Qubit Gates
//////////////////////////////////////////////////////////////////
// Task 2.1. Two-qubit gate - 1
// Input: Two unentangled qubits (stored in an array of length 2).
// The first qubit will be in state |ψ⟩ = α |0⟩ + β |1⟩, the second - in state |0⟩
// (this can be written as two-qubit state (α|0⟩ + β|1⟩) ⊕ |0⟩).
// Goal: Change the two-qubit state to α |00⟩ + β |11⟩.
// Note that unless the starting state of the first qubit was |0⟩ or |1⟩,
// the resulting two-qubit state can not be represented as a tensor product
// the resulting two-qubit state can not be represented as a tensor product
// of the states of individual qubits any longer; thus the qubits become entangled.
operation TwoQubitGate1_Reference (qs : Qubit[]) : ()
{
body
{
operation TwoQubitGate1_Reference (qs : Qubit[]) : Unit {
body (...) {
CNOT(qs[0], qs[1]);
}
adjoint self;
}
// Task 2.2. Two-qubit gate - 2
// Input: Two qubits (stored in an array of length 2)
// in state |+⟩ ⊕ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2.
// Goal: Change the two-qubit state to (|00⟩ + |01⟩ + |10⟩ - |11⟩) / 2.
// Note that while the starting state can be represented as a tensor product of single-qubit states,
// the resulting two-qubit state can not be represented in such a way.
operation TwoQubitGate2_Reference (qs : Qubit[]) : ()
{
body
{
(Controlled Z)([qs[0]], qs[1]);
operation TwoQubitGate2_Reference (qs : Qubit[]) : Unit {
body (...) {
Controlled Z([qs[0]], qs[1]);
}
adjoint self;
}
// Task 2.3. Two-qubit gate - 3
// Input: Two qubits (stored in an array of length 2) in an arbitrary
// Input: Two qubits (stored in an array of length 2) in an arbitrary
// two-qubit state α|00⟩ + β|01⟩ + γ|10⟩ + δ|11⟩.
// Goal: Change the two-qubit state to α|00⟩ + γ|01⟩ + β|10⟩ + δ|11⟩.
operation TwoQubitGate3_Reference (qs : Qubit[]) : ()
{
body
{
operation TwoQubitGate3_Reference (qs : Qubit[]) : Unit {
body (...) {
// Hint: this task can be solved using one primitive gate;
// as an exercise, try to express the solution using several controlled Pauli gates.
CNOT(qs[0], qs[1]);
CNOT(qs[1], qs[0]);
CNOT(qs[0], qs[1]);
}
adjoint self;
}
// Task 2.4. Toffoli gate
// Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩.
// Goal: Flip the state of the third qubit if the state of the first two is |11⟩:
// i.e., change the three-qubit state to
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + θ|110⟩ + η|111⟩.
operation ToffoliGate_Reference (qs : Qubit[]) : ()
{
body
{
operation ToffoliGate_Reference (qs : Qubit[]) : Unit {
body (...) {
CCNOT(qs[0], qs[1], qs[2]);
// alternatively (Controlled X)(qs[0..1], qs[2]);
}
adjoint self;
}
// Task 2.5. Fredkin gate
// Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩.
// Goal: Swap the states of second and third qubit if and only if the state of the first qubit is |1⟩:
// i.e., change the three-qubit state to
// i.e., change the three-qubit state to
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + η|101⟩ + ζ|110⟩ + θ|111⟩.
operation FredkinGate_Reference (qs : Qubit[]) : ()
{
body
{
(Controlled SWAP)([qs[0]], (qs[1], qs[2]));
operation FredkinGate_Reference (qs : Qubit[]) : Unit {
body (...) {
Controlled SWAP([qs[0]], (qs[1], qs[2]));
}
adjoint self;
}
}

Просмотреть файл

@ -1,58 +1,60 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.BasicGates
{
namespace Quantum.Kata.BasicGates {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Basic Gates" quantum kata is a series of exercises designed
// "Basic Gates" quantum kata is a series of exercises designed
// to get you familiar with the basic quantum gates in Q#.
// It covers the following topics:
// - basic single-qubit and multi-qubit gates,
// - adjoint and controlled gates,
// - using gates to modify the state of a qubit.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//
// Most tasks can be done using exactly one gate.
// None of the tasks require measurement, and the tests are written so as to fail if qubit state is measured.
//
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
//////////////////////////////////////////////////////////////////
// Part I. Single-Qubit Gates
//////////////////////////////////////////////////////////////////
// Task 1.1. State flip: |0⟩ to |1⟩ and vice versa
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the state of the qubit to α |1⟩ + β |0⟩.
// Example:
// If the qubit is in state |0⟩, change its state to |1⟩.
// If the qubit is in state |1⟩, change its state to |0⟩.
// Note that this operation is self-adjoint: applying it for a second time
// Example:
// If the qubit is in state |0⟩, change its state to |1⟩.
// If the qubit is in state |1⟩, change its state to |0⟩.
// Note that this operation is self-adjoint: applying it for a second time
// returns the qubit to the original state.
operation StateFlip (q : Qubit) : ()
{
body
{
operation StateFlip (q : Qubit) : Unit {
body (...) {
// The Pauli X gate will change the |0⟩ state to the |1⟩ state and vice versa.
// Type X(q);
// Then rebuild the project and rerun the tests - T11_StateFlip_Test should now pass!
// ...
}
adjoint self;
}
// Task 1.2. Basis change: |0⟩ to |+⟩ and |1⟩ to |-⟩ (and vice versa)
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the state of the qubit as follows:
@ -61,189 +63,201 @@ namespace Quantum.Kata.BasicGates
// If the qubit is in superposition, change its state according to the effect on basis vectors.
// Note: |+⟩ and |-⟩ form a different basis for single-qubit states, called X basis.
// |0⟩ and |1⟩ are called Z basis.
operation BasisChange (q : Qubit) : ()
{
body
{
operation BasisChange (q : Qubit) : Unit {
body (...) {
// ...
}
adjoint self;
}
// Task 1.3. Sign flip: |+⟩ to |-⟩ and vice versa.
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the qubit state to α |0⟩ - β |1⟩ (flip the sign of |1⟩ component of the superposition).
operation SignFlip (q : Qubit) : ()
{
body
{
operation SignFlip (q : Qubit) : Unit {
body (...) {
// ...
}
adjoint self;
}
// Task 1.4*. Amplitude change: |0⟩ to cos(alpha)*|0⟩ + sin(alpha)*|1⟩.
// Inputs:
// Inputs:
// 1) A qubit in state β|0⟩ + γ|1⟩.
// 2) Angle alpha, in radians, represented as Double
// Goal: Change the state of the qubit as follows:
// If the qubit is in state |0⟩, change its state to cos(alpha)*|0⟩ + sin(alpha)*|1⟩.
// If the qubit is in state |1⟩, change its state to -sin(alpha)*|0⟩ + cos(alpha)*|1⟩.
// If the qubit is in superposition, change its state according to the effect on basis vectors.
operation AmplitudeChange (q : Qubit, alpha : Double) : ()
{
body
{
operation AmplitudeChange (q : Qubit, alpha : Double) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.5. Phase flip
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
// Goal: Change the qubit state to α |0⟩ + iβ |1⟩ (flip the phase of |1⟩ component of the superposition).
operation PhaseFlip (q : Qubit) : ()
{
body
{
operation PhaseFlip (q : Qubit) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.6*. Phase change
// Inputs:
// Inputs:
// 1) A qubit in state β|0⟩ + γ|1⟩.
// 2) Angle alpha, in radians, represented as Double
// Goal: Change the state of the qubit as follows:
// If the qubit is in state |0⟩, don't change its state.
// If the qubit is in state |1⟩, change its state to exp(i*alpha)|1⟩.
// If the qubit is in superposition, change its state according to the effect on basis vectors.
operation PhaseChange (q : Qubit, alpha : Double) : ()
{
body
{
operation PhaseChange (q : Qubit, alpha : Double) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.7. Bell state change - 1
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// Goal: Change the two-qubit state to |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2).
operation BellStateChange1 (qs : Qubit[]) : ()
{
body
{
operation BellStateChange1 (qs : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.8. Bell state change - 2
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// Goal: Change the two-qubit state to |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2).
operation BellStateChange2 (qs : Qubit[]) : ()
{
body
{
operation BellStateChange2 (qs : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.9. Bell state change - 3
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// Goal: Change the two-qubit state to |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2).
operation BellStateChange3 (qs : Qubit[]) : ()
{
body
{
operation BellStateChange3 (qs : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
//////////////////////////////////////////////////////////////////
// Part II. Multi-Qubit Gates
//////////////////////////////////////////////////////////////////
// Task 2.1. Two-qubit gate - 1
// Input: Two unentangled qubits (stored in an array of length 2).
// The first qubit will be in state |ψ⟩ = α |0⟩ + β |1⟩, the second - in state |0⟩
// (this can be written as two-qubit state (α|0⟩ + β|1⟩) ⊕ |0⟩).
// Goal: Change the two-qubit state to α |00⟩ + β |11⟩.
// Note that unless the starting state of the first qubit was |0⟩ or |1⟩,
// the resulting two-qubit state can not be represented as a tensor product
// the resulting two-qubit state can not be represented as a tensor product
// of the states of individual qubits any longer; thus the qubits become entangled.
operation TwoQubitGate1 (qs : Qubit[]) : ()
{
body
{
operation TwoQubitGate1 (qs : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint self;
}
// Task 2.2. Two-qubit gate - 2
// Input: Two qubits (stored in an array of length 2)
// in state |+⟩ ⊕ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2.
// Goal: Change the two-qubit state to (|00⟩ + |01⟩ + |10⟩ - |11⟩) / 2.
// Note that while the starting state can be represented as a tensor product of single-qubit states,
// the resulting two-qubit state can not be represented in such a way.
operation TwoQubitGate2 (qs : Qubit[]) : ()
{
body
{
operation TwoQubitGate2 (qs : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint self;
}
// Task 2.3. Two-qubit gate - 3
// Input: Two qubits (stored in an array of length 2) in an arbitrary
// Input: Two qubits (stored in an array of length 2) in an arbitrary
// two-qubit state α|00⟩ + β|01⟩ + γ|10⟩ + δ|11⟩.
// Goal: Change the two-qubit state to α|00⟩ + γ|01⟩ + β|10⟩ + δ|11⟩.
operation TwoQubitGate3 (qs : Qubit[]) : ()
{
body
{
operation TwoQubitGate3 (qs : Qubit[]) : Unit {
body (...) {
// Hint: this task can be solved using one primitive gate;
// as an exercise, try to express the solution using several
// as an exercise, try to express the solution using several
// (possibly controlled) Pauli gates.
// ...
}
adjoint self;
}
// Task 2.4. Toffoli gate
// Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩.
// Goal: Flip the state of the third qubit if the state of the first two is |11⟩:
// i.e., change the three-qubit state to
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + θ|110⟩ + η|111⟩.
operation ToffoliGate (qs : Qubit[]) : ()
{
body
{
operation ToffoliGate (qs : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint self;
}
// Task 2.5. Fredkin gate
// Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩.
// Goal: Swap the states of second and third qubit if and only if the state of the first qubit is |1⟩:
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + η|101⟩ + ζ|110⟩ + θ|111⟩.
operation FredkinGate (qs : Qubit[]) : ()
{
body
{
operation FredkinGate (qs : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint self;
}
}

Просмотреть файл

@ -1,268 +1,234 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.BasicGates
{
namespace Quantum.Kata.BasicGates {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Testing;
// ------------------------------------------------------
// helper wrapper to represent operation on one qubit as an operation on an array of qubits
operation ArrayWrapperOperation (op : ((Qubit) => () : Adjoint), qs : Qubit[]) : ()
{
body
{
operation ArrayWrapperOperation (op : (Qubit => Unit : Adjoint), qs : Qubit[]) : Unit {
body (...) {
op(qs[0]);
}
adjoint
{
(Adjoint op)(qs[0]);
adjoint (...) {
Adjoint op(qs[0]);
}
}
// ------------------------------------------------------
operation T11_StateFlip_Test () : ()
{
body
{
AssertOperationsEqualReferenced(ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _), 1);
}
operation T11_StateFlip_Test () : Unit {
AssertOperationsEqualReferenced(ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _), 1);
}
// ------------------------------------------------------
operation T12_BasisChange_Test () : ()
{
body
{
AssertOperationsEqualReferenced(ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _), 1);
}
operation T12_BasisChange_Test () : Unit {
AssertOperationsEqualReferenced(ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _), 1);
}
// ------------------------------------------------------
operation T13_SignFlip_Test () : ()
{
body
{
AssertOperationsEqualReferenced(ArrayWrapperOperation(SignFlip, _), ArrayWrapperOperation(SignFlip_Reference, _), 1);
}
operation T13_SignFlip_Test () : Unit {
AssertOperationsEqualReferenced(ArrayWrapperOperation(SignFlip, _), ArrayWrapperOperation(SignFlip_Reference, _), 1);
}
// ------------------------------------------------------
operation T14_AmplitudeChange_Test () : ()
{
body
{
for (i in 0..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
AssertOperationsEqualReferenced(ArrayWrapperOperation(AmplitudeChange(_, alpha), _), ArrayWrapperOperation(AmplitudeChange_Reference(_, alpha), _), 1);
}
operation T14_AmplitudeChange_Test () : Unit {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
AssertOperationsEqualReferenced(ArrayWrapperOperation(AmplitudeChange(_, alpha), _), ArrayWrapperOperation(AmplitudeChange_Reference(_, alpha), _), 1);
}
}
// ------------------------------------------------------
operation T15_PhaseFlip_Test () : ()
{
body
{
AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseFlip, _), ArrayWrapperOperation(PhaseFlip_Reference, _), 1);
}
operation T15_PhaseFlip_Test () : Unit {
AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseFlip, _), ArrayWrapperOperation(PhaseFlip_Reference, _), 1);
}
// ------------------------------------------------------
operation T16_PhaseChange_Test () : ()
{
body
{
for (i in 0..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseChange(_, alpha), _), ArrayWrapperOperation(PhaseChange_Reference(_, alpha), _), 1);
}
operation T16_PhaseChange_Test () : Unit {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseChange(_, alpha), _), ArrayWrapperOperation(PhaseChange_Reference(_, alpha), _), 1);
}
}
// ------------------------------------------------------
// 0 - |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
// 1 - |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
// 2 - |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
// 3 - |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
operation StatePrep_BellState (qs : Qubit[], state : Int) : () {
body {
operation StatePrep_BellState (qs : Qubit[], state : Int) : Unit {
body (...) {
H(qs[0]);
CNOT(qs[0], qs[1]);
// now we have |00⟩ + |11⟩ - modify it based on state arg
if (state % 2 == 1) {
// negative phase
Z(qs[1]);
}
if (state / 2 == 1) {
X(qs[1]);
}
}
adjoint auto;
adjoint invert;
}
// ------------------------------------------------------
operation VerifyBellStateConversion(
testOp : ((Qubit[]) => ()),
startState : Int,
targetState : Int) : () {
body {
using (qs = Qubit[2])
{
// prepare Bell state startState
StatePrep_BellState(qs, startState);
// apply operation that needs to be tested
testOp(qs);
// verify the result by applying adjoint of state prep for target state
(Adjoint StatePrep_BellState)(qs, targetState);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
operation VerifyBellStateConversion (testOp : (Qubit[] => Unit), startState : Int, targetState : Int) : Unit {
using (qs = Qubit[2]) {
// prepare Bell state startState
StatePrep_BellState(qs, startState);
// apply operation that needs to be tested
testOp(qs);
// verify the result by applying adjoint of state prep for target state
Adjoint StatePrep_BellState(qs, targetState);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
// ------------------------------------------------------
operation T17_BellStateChange1_Test () : ()
{
body
{
VerifyBellStateConversion(BellStateChange1, 0, 1);
}
operation T17_BellStateChange1_Test () : Unit {
VerifyBellStateConversion(BellStateChange1, 0, 1);
}
// ------------------------------------------------------
operation T18_BellStateChange2_Test () : ()
{
body
{
VerifyBellStateConversion(BellStateChange2, 0, 2);
}
operation T18_BellStateChange2_Test () : Unit {
VerifyBellStateConversion(BellStateChange2, 0, 2);
}
// ------------------------------------------------------
operation T19_BellStateChange3_Test () : ()
{
body
{
VerifyBellStateConversion(BellStateChange3, 0, 3);
}
operation T19_BellStateChange3_Test () : Unit {
VerifyBellStateConversion(BellStateChange3, 0, 3);
}
// ------------------------------------------------------
// prepare state |A⟩ = cos(α) * |0⟩ + sin(α) * |1⟩
operation StatePrep_A (alpha : Double, q : Qubit) : () {
body {
operation StatePrep_A (alpha : Double, q : Qubit) : Unit {
body (...) {
Ry(2.0 * alpha, q);
}
adjoint auto;
adjoint invert;
}
// ------------------------------------------------------
operation T21_TwoQubitGate1_Test () : ()
{
body
{
// Note that the way the problem is formulated, we can't just compare two unitaries,
// we need to create an input state |A⟩ and check that the output state is correct
using (qs = Qubit[2])
{
for (i in 0..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
// prepare A state
StatePrep_A(alpha, qs[0]);
// apply operation that needs to be tested
TwoQubitGate1(qs);
// apply adjoint reference operation and adjoint of state prep
(Adjoint TwoQubitGate1_Reference)(qs);
(Adjoint StatePrep_A)(alpha, qs[0]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
}
}
// ------------------------------------------------------
// prepare state |+⟩ ⊕ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2.
operation StatePrep_PlusPlus (qs : Qubit[]) : () {
body {
ApplyToEachA(H, qs);
}
adjoint auto;
}
// ------------------------------------------------------
operation T22_TwoQubitGate2_Test () : ()
{
body
{
using (qs = Qubit[2])
{
// prepare |+⟩ ⊕ |+⟩ state
StatePrep_PlusPlus(qs);
operation T21_TwoQubitGate1_Test () : Unit {
// Note that the way the problem is formulated, we can't just compare two unitaries,
// we need to create an input state |A⟩ and check that the output state is correct
using (qs = Qubit[2]) {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
// prepare A state
StatePrep_A(alpha, qs[0]);
// apply operation that needs to be tested
TwoQubitGate2(qs);
TwoQubitGate1(qs);
// apply adjoint reference operation and adjoint of state prep
(Adjoint TwoQubitGate2_Reference)(qs);
(Adjoint StatePrep_PlusPlus)(qs);
Adjoint TwoQubitGate1_Reference(qs);
Adjoint StatePrep_A(alpha, qs[0]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
}
// ------------------------------------------------------
operation SwapWrapper (qs : Qubit[]) : ()
{
body
{
// prepare state |+⟩ ⊕ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2.
operation StatePrep_PlusPlus (qs : Qubit[]) : Unit {
body (...) {
ApplyToEachA(H, qs);
}
adjoint invert;
}
// ------------------------------------------------------
operation T22_TwoQubitGate2_Test () : Unit {
using (qs = Qubit[2]) {
// prepare |+⟩ ⊕ |+⟩ state
StatePrep_PlusPlus(qs);
// apply operation that needs to be tested
TwoQubitGate2(qs);
// apply adjoint reference operation and adjoint of state prep
Adjoint TwoQubitGate2_Reference(qs);
Adjoint StatePrep_PlusPlus(qs);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
// ------------------------------------------------------
operation SwapWrapper (qs : Qubit[]) : Unit {
body (...) {
SWAP(qs[0], qs[1]);
}
adjoint self;
}
operation T23_TwoQubitGate3_Test () : ()
{
body
{
AssertOperationsEqualReferenced(SwapWrapper, TwoQubitGate3_Reference, 2);
AssertOperationsEqualReferenced(TwoQubitGate3, TwoQubitGate3_Reference, 2);
}
operation T23_TwoQubitGate3_Test () : Unit {
AssertOperationsEqualReferenced(SwapWrapper, TwoQubitGate3_Reference, 2);
AssertOperationsEqualReferenced(TwoQubitGate3, TwoQubitGate3_Reference, 2);
}
// ------------------------------------------------------
operation T24_ToffoliGate_Test () : ()
{
body
{
AssertOperationsEqualReferenced(ToffoliGate, ToffoliGate_Reference, 3);
}
operation T24_ToffoliGate_Test () : Unit {
AssertOperationsEqualReferenced(ToffoliGate, ToffoliGate_Reference, 3);
}
// ------------------------------------------------------
operation T25_FredkinGate_Test () : ()
{
body
{
AssertOperationsEqualReferenced(FredkinGate, FredkinGate_Reference, 3);
}
operation T25_FredkinGate_Test () : Unit {
AssertOperationsEqualReferenced(FredkinGate, FredkinGate_Reference, 3);
}
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.DeutschJozsaAlgorithm</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,130 +1,135 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.DeutschJozsaAlgorithm
{
namespace Quantum.Kata.DeutschJozsaAlgorithm {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Part I. Oracles
//////////////////////////////////////////////////////////////////
// Task 1.1. f(x) = 0
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_Zero_Reference (x : Qubit[], y : Qubit) : ()
{
body
{
operation Oracle_Zero_Reference (x : Qubit[], y : Qubit) : Unit {
body (...) {
// Since f(x) = 0 for all values of x, |y ⊕ f(x)⟩ = |y⟩.
// This means that the operation doesn't need to do any transformation to the inputs.
// Build the project and run the tests to see that T01_Oracle_Zero_Test test passes.
}
adjoint auto;
adjoint invert;
}
// Task 1.2. f(x) = 1
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_One_Reference (x : Qubit[], y : Qubit) : ()
{
body
{
operation Oracle_One_Reference (x : Qubit[], y : Qubit) : Unit {
body (...) {
// Since f(x) = 1 for all values of x, |y ⊕ f(x)⟩ = |y ⊕ 1⟩ = |NOT y⟩.
// This means that the operation needs to flip qubit y (i.e. transform |0⟩ to |1⟩ and vice versa).
X(y);
}
adjoint auto;
adjoint invert;
}
// Task 1.3. f(x) = xₖ (the value of k-th qubit)
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) 0-based index of the qubit from input register (0 <= k < N)
// Goal: transform state |x, y⟩ into state |x, y ⊕ xₖ⟩ (⊕ is addition modulo 2).
operation Oracle_Kth_Qubit_Reference (x : Qubit[], y : Qubit, k : Int) : ()
{
body
{
operation Oracle_Kth_Qubit_Reference (x : Qubit[], y : Qubit, k : Int) : Unit {
body (...) {
AssertBoolEqual(0 <= k && k < Length(x), true, "k should be between 0 and N-1, inclusive");
CNOT(x[k], y);
}
adjoint auto;
adjoint invert;
}
// Task 1.4. f(x) = 1 if x has odd number of 1s, and 0 otherwise
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_OddNumberOfOnes_Reference (x : Qubit[], y : Qubit) : ()
{
body
{
operation Oracle_OddNumberOfOnes_Reference (x : Qubit[], y : Qubit) : Unit {
body (...) {
// Hint: f(x) can be represented as x_0 ⊕ x_1 ⊕ ... ⊕ x_(N-1)
for (i in 0..Length(x)-1) {
for (i in 0 .. Length(x) - 1) {
CNOT(x[i], y);
}
// alternative solution: ApplyToEachA(CNOT(_, y), x);
}
adjoint auto;
adjoint invert;
}
// Task 1.5. f(x) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for a given bit vector r (scalar product function)
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) a bit vector of length N represented as Int[]
// You are guaranteed that the qubit array and the bit vector have the same length.
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
//
// Note: the functions featured in tasks 1.1, 1.3 and 1.4 are special cases of this function.
operation Oracle_ProductFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : ()
{
body
{
operation Oracle_ProductFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : Unit {
body (...) {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
for (i in 0..Length(x)-1) {
for (i in 0 .. Length(x) - 1) {
if (r[i] == 1) {
CNOT(x[i], y);
}
}
}
adjoint auto;
adjoint invert;
}
// Task 1.6. f(x) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) modulo 2 for a given bit vector r
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) a bit vector of length N represented as Int[]
// You are guaranteed that the qubit array and the bit vector have the same length.
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_ProductWithNegationFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : ()
{
body
{
operation Oracle_ProductWithNegationFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : Unit {
body (...) {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
for (i in 0..Length(x)-1) {
for (i in 0 .. Length(x) - 1) {
if (r[i] == 1) {
CNOT(x[i], y);
} else {
@ -135,59 +140,65 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
}
}
}
adjoint auto;
adjoint invert;
}
// Task 1.7. f(x) = Σᵢ 𝑥ᵢ + (1 if prefix of x is equal to the given bit vector, and 0 otherwise) modulo 2
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) a bit vector of length P represented as Int[] (1 <= P <= N)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
//
// A prefix of length k of a state |x⟩ = |x₁, ..., xₙ⟩ is the state of its first k qubits |x₁, ..., xₖ⟩.
// For example, a prefix of length 2 of a state |0110⟩ is 01.
operation Oracle_HammingWithPrefix_Reference (x : Qubit[], y : Qubit, prefix : Int[]) : ()
{
body
{
operation Oracle_HammingWithPrefix_Reference (x : Qubit[], y : Qubit, prefix : Int[]) : Unit {
body (...) {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
let P = Length(prefix);
AssertBoolEqual(1 <= P && P <= Length(x), true, "P should be between 1 and N, inclusive");
// Hint: the first part of the function is the same as in task 1.4
for (i in 0..Length(x)-1) {
for (i in 0 .. Length(x) - 1) {
CNOT(x[i], y);
}
// add check for prefix as a multicontrolled NOT
// true bits of r correspond to 1-controls, false bits - to 0-controls
for (i in 0..P-1) {
for (i in 0 .. P - 1) {
if (prefix[i] == 0) {
X(x[i]);
}
}
(Controlled X)(x[0..P-1], y);
Controlled X(x[0 .. P - 1], y);
// uncompute changes done to input register
for (i in 0..P-1) {
for (i in 0 .. P - 1) {
if (prefix[i] == 0) {
X(x[i]);
}
}
}
adjoint auto;
adjoint invert;
}
// Task 1.8*. f(x) = 1 if x has two or three bits (out of three) set to 1, and 0 otherwise (majority function)
// Inputs:
// Inputs:
// 1) 3 qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_MajorityFunction_Reference (x : Qubit[], y : Qubit) : ()
{
body
{
operation Oracle_MajorityFunction_Reference (x : Qubit[], y : Qubit) : Unit {
body (...) {
// The following line enforces the constraint on the input array.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertBoolEqual(3 == Length(x), true, "x should have exactly 3 qubits");
@ -197,14 +208,15 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
CCNOT(x[0], x[2], y);
CCNOT(x[1], x[2], y);
}
adjoint auto;
adjoint invert;
}
//////////////////////////////////////////////////////////////////
// Part II. Bernstein-Vazirani Algorithm
//////////////////////////////////////////////////////////////////
// Task 2.1. State preparation for Bernstein-Vazirani algorithm
// Inputs:
// 1) N qubits in |0⟩ state (query register)
@ -213,17 +225,18 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// 1) create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩ on query register
// (i.e. state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N) )
// 2) create |-⟩ state (|-⟩ = (|0⟩ - |1⟩) / sqrt(2)) on answer register
operation BV_StatePrep_Reference (query : Qubit[], answer : Qubit) : ()
{
body
{
operation BV_StatePrep_Reference (query : Qubit[], answer : Qubit) : Unit {
body (...) {
ApplyToEachA(H, query);
X(answer);
H(answer);
}
adjoint auto;
adjoint invert;
}
// Task 2.2. Bernstein-Vazirani algorithm implementation
// Inputs:
// 1) the number of qubits in the input register N for the function f
@ -234,94 +247,91 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// You have implemented the oracle implementing the scalar product function in task 1.5.
// Output:
// A bit vector r reconstructed from the function
//
// Note: a trivial approach is to call the oracle N times:
// Note: a trivial approach is to call the oracle N times:
// |10...0⟩|0⟩ = |10...0⟩|r₀⟩, |010...0⟩|0⟩ = |010...0⟩|r₁⟩ and so on.
// Quantum computing allows to perform this task in just one call to the oracle; try to implement this algorithm.
operation BV_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => ())) : Int[]
{
body
{
mutable r = new Int[N];
// allocate N+1 qubits
using (qs = Qubit[N+1]) {
// split allocated qubits into input register and answer register
let x = qs[0..N-1];
let y = qs[N];
// prepare qubits in the right state
BV_StatePrep_Reference(x, y);
// apply oracle
Uf(x, y);
// apply Hadamard to each qubit of the input register
ApplyToEach(H, x);
// measure all qubits of the input register;
// the result of each measurement is converted to a Bool
for (i in 0..N-1) {
if (M(x[i]) != Zero) {
set r[i] = 1;
}
operation BV_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Int[] {
mutable r = new Int[N];
// allocate N+1 qubits
using (qs = Qubit[N + 1]) {
// split allocated qubits into input register and answer register
let x = qs[0 .. N - 1];
let y = qs[N];
// prepare qubits in the right state
BV_StatePrep_Reference(x, y);
// apply oracle
Uf(x, y);
// apply Hadamard to each qubit of the input register
ApplyToEach(H, x);
// measure all qubits of the input register;
// the result of each measurement is converted to a Bool
for (i in 0 .. N - 1) {
if (M(x[i]) != Zero) {
set r[i] = 1;
}
// before releasing the qubits make sure they are all in |0⟩ state
ResetAll(qs);
}
return r;
// before releasing the qubits make sure they are all in |0⟩ state
ResetAll(qs);
}
return r;
}
//////////////////////////////////////////////////////////////////
// Part III. Deutsch-Jozsa Algorithm
//////////////////////////////////////////////////////////////////
// Task 3.1. Deutsch-Jozsa algorithm implementation
// Inputs:
// 1) the number of qubits in the input register N for the function f
// 2) a quantum operation which implements the oracle |x⟩|y⟩ -> |x⟩|y ⊕ f(x)⟩, where
// x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function
// You are guaranteed that the function f implemented by the oracle is either
// constant (returns 0 on all inputs or 1 on all inputs) or
// You are guaranteed that the function f implemented by the oracle is either
// constant (returns 0 on all inputs or 1 on all inputs) or
// balanced (returns 0 on exactly one half of the input domain and 1 on the other half).
// Output:
// true if the function f is constant
// true if the function f is constant
// false if the function f is balanced
//
// Note: a trivial approach is to call the oracle multiple times:
// Note: a trivial approach is to call the oracle multiple times:
// if the values for more than half of the possible inputs are the same, the function is constant.
// Quantum computing allows to perform this task in just one call to the oracle; try to implement this algorithm.
operation DJ_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => ())) : Bool
{
body
{
// Declare variable in which the result will be accumulated;
// this variable has to be mutable to allow updating it.
mutable isConstantFunction = true;
// Hint: even though Deutsch-Jozsa algorithm operates on a wider class of functions
// than Bernstein-Vazirani (i.e. functions which can not be represented as a scalar product, such as f(x) = 1),
// it can be expressed as running Bernstein-Vazirani algorithm
// and then post-processing the return value classically:
// the function is constant if and only if all elements of the returned array are false
let r = BV_Algorithm_Reference(N, Uf);
for (i in 0..N-1) {
set isConstantFunction = isConstantFunction && (r[i] == 0);
}
return isConstantFunction;
operation DJ_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Bool {
// Declare variable in which the result will be accumulated;
// this variable has to be mutable to allow updating it.
mutable isConstantFunction = true;
// Hint: even though Deutsch-Jozsa algorithm operates on a wider class of functions
// than Bernstein-Vazirani (i.e. functions which can not be represented as a scalar product, such as f(x) = 1),
// it can be expressed as running Bernstein-Vazirani algorithm
// and then post-processing the return value classically:
// the function is constant if and only if all elements of the returned array are false
let r = BV_Algorithm_Reference(N, Uf);
for (i in 0 .. N - 1) {
set isConstantFunction = isConstantFunction && r[i] == 0;
}
return isConstantFunction;
}
//////////////////////////////////////////////////////////////////
// Part IV. Come up with your own algorithm!
//////////////////////////////////////////////////////////////////
// Task 4.1. Reconstruct the oracle from task 1.6
// Inputs:
// 1) the number of qubits in the input register N for the function f
@ -332,42 +342,41 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// You have implemented the oracle implementing this function in task 1.6.
// Output:
// A bit vector r which generates the same oracle as the one you are given
operation Noname_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => ())) : Int[]
{
body
{
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable r = new Int[N];
using (qs = Qubit[N+1]) {
// split allocated qubits into input register and answer register
let x = qs[0..N-1];
let y = qs[N];
// apply oracle to qubits in all 0 state
Uf(x, y);
// f(x) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) = 2 Σᵢ 𝑟ᵢ 𝑥ᵢ + Σᵢ 𝑟ᵢ + Σᵢ 𝑥ᵢ + N = Σᵢ 𝑟ᵢ + N
// remove the N from the expression
if (N % 2 == 1) {
X(y);
}
// now y = Σᵢ 𝑟ᵢ
// measure the output register
let m = M(y);
if (m == One) {
// adjust parity of bit vector r
set r[0] = 1;
}
// before releasing the qubits make sure they are all in |0⟩ state
ResetAll(qs);
operation Noname_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Int[] {
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable r = new Int[N];
using (qs = Qubit[N + 1]) {
// split allocated qubits into input register and answer register
let x = qs[0 .. N - 1];
let y = qs[N];
// apply oracle to qubits in all 0 state
Uf(x, y);
// f(x) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) = 2 Σᵢ 𝑟ᵢ 𝑥ᵢ + Σᵢ 𝑟ᵢ + Σᵢ 𝑥ᵢ + N = Σᵢ 𝑟ᵢ + N
// remove the N from the expression
if (N % 2 == 1) {
X(y);
}
return r;
// now y = Σᵢ 𝑟ᵢ
// measure the output register
let m = M(y);
if (m == One) {
// adjust parity of bit vector r
set r[0] = 1;
}
// before releasing the qubits make sure they are all in |0⟩ state
ResetAll(qs);
}
return r;
}
}

Просмотреть файл

@ -1,32 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.DeutschJozsaAlgorithm
{
namespace Quantum.Kata.DeutschJozsaAlgorithm {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Deutsch-Jozsa algorithm" quantum kata is a series of exercises designed
// "Deutsch-Jozsa algorithm" quantum kata is a series of exercises designed
// to get you familiar with programming in Q#.
// It covers the following topics:
// - writing oracles (quantum operations which implement certain classical functions),
// - Bernstein-Vazirani algorithm for recovering the parameters of a scalar product function,
// - Deutsch-Jozsa algorithm for recognizing a function as constant or balanced, and
// - writing tests in Q#.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//////////////////////////////////////////////////////////////////
// Part I. Oracles
//////////////////////////////////////////////////////////////////
// In this section you will implement oracles defined by classical functions using the following rules:
// - a function f(𝑥₀, …, 𝑥ₙ₋₁) with N bits of input x = (𝑥₀, …, 𝑥ₙ₋₁) and 1 bit of output y
// defines an oracle which acts on N input qubits and 1 output qubit.
@ -34,73 +35,61 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// |x⟩ |y⟩ -> |x⟩ |y ⊕ f(x)⟩ (⊕ is addition modulo 2)
// - the oracle effect on qubits in superposition is defined following the linearity of quantum operations.
// - the oracle must act properly on qubits in all possible input states.
// Task 1.1. f(x) = 0
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_Zero (x : Qubit[], y : Qubit) : ()
{
body
{
// Since f(x) = 0 for all values of x, |y ⊕ f(x)⟩ = |y⟩.
// This means that the operation doesn't need to do any transformation to the inputs.
// Build the project and run the tests to see that T01_Oracle_Zero_Test test passes.
}
operation Oracle_Zero (x : Qubit[], y : Qubit) : Unit {
// Since f(x) = 0 for all values of x, |y ⊕ f(x)⟩ = |y⟩.
// This means that the operation doesn't need to do any transformation to the inputs.
// Build the project and run the tests to see that T01_Oracle_Zero_Test test passes.
}
// Task 1.2. f(x) = 1
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_One (x : Qubit[], y : Qubit) : ()
{
body
{
// Since f(x) = 1 for all values of x, |y ⊕ f(x)⟩ = |y ⊕ 1⟩ = |NOT y⟩.
// This means that the operation needs to flip qubit y (i.e. transform |0⟩ to |1⟩ and vice versa).
operation Oracle_One (x : Qubit[], y : Qubit) : Unit {
// Since f(x) = 1 for all values of x, |y ⊕ f(x)⟩ = |y ⊕ 1⟩ = |NOT y⟩.
// This means that the operation needs to flip qubit y (i.e. transform |0⟩ to |1⟩ and vice versa).
// ...
}
// ...
}
// Task 1.3. f(x) = xₖ (the value of k-th qubit)
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) 0-based index of the qubit from input register (0 <= k < N)
// Goal: transform state |x, y⟩ into state |x, y ⊕ xₖ⟩ (⊕ is addition modulo 2).
operation Oracle_Kth_Qubit (x : Qubit[], y : Qubit, k : Int) : ()
{
body
{
// The following line enforces the constraints on the value of k that you are given.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertBoolEqual(0 <= k && k < Length(x), true, "k should be between 0 and N-1, inclusive");
operation Oracle_Kth_Qubit (x : Qubit[], y : Qubit, k : Int) : Unit {
// The following line enforces the constraints on the value of k that you are given.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertBoolEqual(0 <= k && k < Length(x), true, "k should be between 0 and N-1, inclusive");
// ...
}
// ...
}
// Task 1.4. f(x) = 1 if x has odd number of 1s, and 0 otherwise
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_OddNumberOfOnes (x : Qubit[], y : Qubit) : ()
{
body
{
// Hint: f(x) can be represented as x_0 ⊕ x_1 ⊕ ... ⊕ x_(N-1)
operation Oracle_OddNumberOfOnes (x : Qubit[], y : Qubit) : Unit {
// Hint: f(x) can be represented as x_0 ⊕ x_1 ⊕ ... ⊕ x_(N-1)
// ...
}
// ...
}
// Task 1.5. f(x) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for a given bit vector r (scalar product function)
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) a bit vector of length N represented as Int[]
@ -108,90 +97,77 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
//
// Note: the functions featured in tasks 1.1, 1.3 and 1.4 are special cases of this function.
operation Oracle_ProductFunction (x : Qubit[], y : Qubit, r : Int[]) : ()
{
body
{
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
operation Oracle_ProductFunction (x : Qubit[], y : Qubit, r : Int[]) : Unit {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
// ...
}
// ...
}
// Task 1.6. f(x) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) modulo 2 for a given bit vector r
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) a bit vector of length N represented as Int[]
// You are guaranteed that the qubit array and the bit vector have the same length.
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_ProductWithNegationFunction (x : Qubit[], y : Qubit, r : Int[]) : ()
{
body
{
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
operation Oracle_ProductWithNegationFunction (x : Qubit[], y : Qubit, r : Int[]) : Unit {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
// ...
}
// ...
}
// Task 1.7. f(x) = Σᵢ 𝑥ᵢ + (1 if prefix of x is equal to the given bit vector, and 0 otherwise) modulo 2
// Inputs:
// Inputs:
// 1) N qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// 3) a bit vector of length P represented as Int[] (1 <= P <= N)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
//
//
// A prefix of length k of a state |x⟩ = |x₁, ..., xₙ⟩ is the state of its first k qubits |x₁, ..., xₖ⟩.
// For example, a prefix of length 2 of a state |0110⟩ is 01.
operation Oracle_HammingWithPrefix (x : Qubit[], y : Qubit, prefix : Int[]) : ()
{
body
{
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
let P = Length(prefix);
AssertBoolEqual(1 <= P && P <= Length(x), true, "P should be between 1 and N, inclusive");
operation Oracle_HammingWithPrefix (x : Qubit[], y : Qubit, prefix : Int[]) : Unit {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
let P = Length(prefix);
AssertBoolEqual(1 <= P && P <= Length(x), true, "P should be between 1 and N, inclusive");
// Hint: the first part of the function is the same as in task 1.4
// Hint: the first part of the function is the same as in task 1.4
// ...
// ...
// Hint: you can use Controlled functor to perform multicontrolled gates
// (gates with multiple control qubits).
// Hint: you can use Controlled functor to perform multicontrolled gates
// (gates with multiple control qubits).
// ...
}
// ...
}
// Task 1.8*. f(x) = 1 if x has two or three bits (out of three) set to 1, and 0 otherwise (majority function)
// Inputs:
// Inputs:
// 1) 3 qubits in arbitrary state |x⟩ (input register)
// 2) a qubit in arbitrary state |y⟩ (output qubit)
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
operation Oracle_MajorityFunction (x : Qubit[], y : Qubit) : ()
{
body
{
// The following line enforces the constraint on the input array.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertBoolEqual(3 == Length(x), true, "x should have exactly 3 qubits");
// Hint: represent f(x) in terms of AND and ⊕ operations
operation Oracle_MajorityFunction (x : Qubit[], y : Qubit) : Unit {
// The following line enforces the constraint on the input array.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertBoolEqual(3 == Length(x), true, "x should have exactly 3 qubits");
// ...
}
// Hint: represent f(x) in terms of AND and ⊕ operations
// ...
}
//////////////////////////////////////////////////////////////////
// Part II. Bernstein-Vazirani Algorithm
//////////////////////////////////////////////////////////////////
// Task 2.1. State preparation for Bernstein-Vazirani algorithm
// Inputs:
// 1) N qubits in |0⟩ state (query register)
@ -200,15 +176,16 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// 1) create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩ on query register
// (i.e. state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N) )
// 2) create |-⟩ state (|-⟩ = (|0⟩ - |1⟩) / sqrt(2)) on answer register
operation BV_StatePrep (query : Qubit[], answer : Qubit) : ()
{
body
{
operation BV_StatePrep (query : Qubit[], answer : Qubit) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 2.2. Bernstein-Vazirani algorithm implementation
// Inputs:
// 1) the number of qubits in the input register N for the function f
@ -220,111 +197,99 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// Output:
// A bit vector r reconstructed from the function
//
// Note: a trivial approach is to call the oracle N times:
// Note: a trivial approach is to call the oracle N times:
// |10...0⟩|0⟩ = |10...0⟩|r₀⟩, |010...0⟩|0⟩ = |010...0⟩|r₁⟩ and so on.
// Quantum computing allows to perform this task in just one call to the oracle; try to implement this algorithm.
operation BV_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => ())) : Int[]
{
body
{
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable r = new Int[N];
operation BV_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Int[] {
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable r = new Int[N];
// ...
// ...
return r;
}
return r;
}
// Task 2.3. Testing Bernstein-Vazirani algorithm
// Goal: use your implementation of Bernstein-Vazirani algorithm from task 2.2 to figure out
// Goal: use your implementation of Bernstein-Vazirani algorithm from task 2.2 to figure out
// what bit vector the scalar product function oracle from task 1.5 was using.
// As a reminder, this oracle creates an operation f(x) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for a given bit vector r,
// and Bernstein-Vazirani algorithm recovers that bit vector given the operation.
operation BV_Test () : ()
{
body
{
// Hint: use Oracle_ProductFunction to implement the scalar product function oracle passed to BV_Algorithm.
// Since Oracle_ProductFunction takes three arguments (Qubit[], Qubit and Int[]),
// and the operation passed to BV_Algorithm must take two arguments (Qubit[] and Qubit),
// you need to use partial application to fix the third argument (a specific value of a bit vector).
//
// You might want to use something like the following:
// let oracle = Oracle_ProductFunction(_, _, [...your bit vector here...]);
operation BV_Test () : Unit {
// Hint: use Oracle_ProductFunction to implement the scalar product function oracle passed to BV_Algorithm.
// Since Oracle_ProductFunction takes three arguments (Qubit[], Qubit and Int[]),
// and the operation passed to BV_Algorithm must take two arguments (Qubit[] and Qubit),
// you need to use partial application to fix the third argument (a specific value of a bit vector).
//
// You might want to use something like the following:
// let oracle = Oracle_ProductFunction(_, _, [...your bit vector here...]);
// Hint: use AssertIntArrayEqual function to assert that the return value of BV_Algorithm operation
// matches the expected value (i.e. the bit vector passed to Oracle_ProductFunction).
// Hint: use AssertIntArrayEqual function to assert that the return value of BV_Algorithm operation
// matches the expected value (i.e. the bit vector passed to Oracle_ProductFunction).
// BV_Test appears in the list of unit tests for the solution; run it to verify your code.
// BV_Test appears in the list of unit tests for the solution; run it to verify your code.
// ...
}
// ...
}
//////////////////////////////////////////////////////////////////
// Part III. Deutsch-Jozsa Algorithm
//////////////////////////////////////////////////////////////////
// Task 3.1. Deutsch-Jozsa algorithm implementation
// Inputs:
// 1) the number of qubits in the input register N for the function f
// 2) a quantum operation which implements the oracle |x⟩|y⟩ -> |x⟩|y ⊕ f(x)⟩, where
// x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function
// You are guaranteed that the function f implemented by the oracle is either
// constant (returns 0 on all inputs or 1 on all inputs) or
// You are guaranteed that the function f implemented by the oracle is either
// constant (returns 0 on all inputs or 1 on all inputs) or
// balanced (returns 0 on exactly one half of the input domain and 1 on the other half).
// Output:
// true if the function f is constant
// true if the function f is constant
// false if the function f is balanced
//
// Note: a trivial approach is to call the oracle multiple times:
// Note: a trivial approach is to call the oracle multiple times:
// if the values for more than half of the possible inputs are the same, the function is constant.
// Quantum computing allows to perform this task in just one call to the oracle; try to implement this algorithm.
operation DJ_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => ())) : Bool
{
body
{
// Declare Bool variable in which the result will be accumulated;
// this variable has to be mutable to allow updating it.
mutable isConstantFunction = true;
operation DJ_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Bool {
// Declare Bool variable in which the result will be accumulated;
// this variable has to be mutable to allow updating it.
mutable isConstantFunction = true;
// Hint: even though Deutsch-Jozsa algorithm operates on a wider class of functions
// than Bernstein-Vazirani (i.e. functions which can not be represented as a scalar product, such as f(x) = 1),
// it can be expressed as running Bernstein-Vazirani algorithm
// and then post-processing the return value classically
// ...
// Hint: even though Deutsch-Jozsa algorithm operates on a wider class of functions
// than Bernstein-Vazirani (i.e. functions which can not be represented as a scalar product, such as f(x) = 1),
// it can be expressed as running Bernstein-Vazirani algorithm
// and then post-processing the return value classically
// ...
return isConstantFunction;
}
return isConstantFunction;
}
// Task 3.2. Testing Deutsch-Jozsa algorithm
// Goal: use your implementation of Deutsch-Jozsa algorithm from task 3.1 to test
// Goal: use your implementation of Deutsch-Jozsa algorithm from task 3.1 to test
// each of the oracles you've implemented in part I for being constant or balanced.
operation DJ_Test () : ()
{
body
{
// Hint: you will need to use partial application to test ones such as Oracle_Kth_Qubit and Oracle_ProductFunction;
// see task 2.3 for a description of how to do that.
operation DJ_Test () : Unit {
// Hint: you will need to use partial application to test ones such as Oracle_Kth_Qubit and Oracle_ProductFunction;
// see task 2.3 for a description of how to do that.
// Hint: use AssertBoolEqual function to assert that the return value of DJ_Algorithm operation matches the expected value
// Hint: use AssertBoolEqual function to assert that the return value of DJ_Algorithm operation matches the expected value
// DJ_Test appears in the list of unit tests for the solution; run it to verify your code.
// DJ_Test appears in the list of unit tests for the solution; run it to verify your code.
// ...
}
// ...
}
//////////////////////////////////////////////////////////////////
// Part IV. Come up with your own algorithm!
//////////////////////////////////////////////////////////////////
// Task 4.1. Reconstruct the oracle from task 1.6
// Inputs:
// 1) the number of qubits in the input register N for the function f
@ -335,20 +300,17 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm
// You have implemented the oracle implementing this function in task 1.6.
// Output:
// A bit vector r which generates the same oracle as the one you are given
operation Noname_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => ())) : Int[]
{
body
{
// Hint: The bit vector r does not need to be the same as the one used by the oracle,
// it just needs to produce equivalent results.
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable r = new Int[N];
// ...
return r;
}
operation Noname_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Int[] {
// Hint: The bit vector r does not need to be the same as the one used by the oracle,
// it just needs to produce equivalent results.
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable r = new Int[N];
// ...
return r;
}
}

Просмотреть файл

@ -1,348 +1,315 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.DeutschJozsaAlgorithm
{
namespace Quantum.Kata.DeutschJozsaAlgorithm {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
// ------------------------------------------------------
operation ApplyOracle (qs : Qubit[], oracle : ((Qubit[], Qubit) => ())) : ()
{
body
{
let N = Length(qs);
oracle(qs[0..N-2], qs[N-1]);
}
operation ApplyOracle (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit)) : Unit {
let N = Length(qs);
oracle(qs[0 .. N - 2], qs[N - 1]);
}
// ------------------------------------------------------
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => () : Adjoint)) : ()
{
body
{
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
body (...) {
let N = Length(qs);
oracle(qs[0..N-2], qs[N-1]);
oracle(qs[0 .. N - 2], qs[N - 1]);
}
adjoint auto;
adjoint invert;
}
// ------------------------------------------------------
operation AssertTwoOraclesAreEqual (nQubits : Range,
oracle1 : ((Qubit[], Qubit) => ()),
oracle2 : ((Qubit[], Qubit) => () : Adjoint)) : ()
{
body
{
let sol = ApplyOracle(_, oracle1);
let refSol = ApplyOracleA(_, oracle2);
for (i in nQubits) {
AssertOperationsEqualReferenced(sol, refSol, i+1);
oracle1 : ((Qubit[], Qubit) => Unit),
oracle2 : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
let sol = ApplyOracle(_, oracle1);
let refSol = ApplyOracleA(_, oracle2);
for (i in nQubits) {
AssertOperationsEqualReferenced(sol, refSol, i + 1);
}
}
// ------------------------------------------------------
operation T11_Oracle_Zero_Test () : Unit {
AssertTwoOraclesAreEqual(1 .. 10, Oracle_Zero, Oracle_Zero_Reference);
}
// ------------------------------------------------------
operation T12_Oracle_One_Test () : Unit {
AssertTwoOraclesAreEqual(1 .. 10, Oracle_One, Oracle_One_Reference);
}
// ------------------------------------------------------
operation T13_Oracle_Kth_Qubit_Test () : Unit {
let maxQ = 6;
// loop over index of the qubit to be used
for (k in 0 .. maxQ - 1) {
// number of qubits to try is from k+1 to 6
AssertTwoOraclesAreEqual(k + 1 .. maxQ, Oracle_Kth_Qubit(_, _, k), Oracle_Kth_Qubit_Reference(_, _, k));
}
}
// ------------------------------------------------------
operation T14_Oracle_OddNumberOfOnes_Test () : Unit {
// cross-test: for 1 qubit it's the same as Kth_Qubit for k = 0
AssertTwoOraclesAreEqual(1 .. 1, Oracle_OddNumberOfOnes, Oracle_Kth_Qubit_Reference(_, _, 0));
AssertTwoOraclesAreEqual(1 .. 10, Oracle_OddNumberOfOnes, Oracle_OddNumberOfOnes_Reference);
}
// ------------------------------------------------------
operation AssertTwoOraclesWithIntAreEqual (r : Int[],
oracle1 : ((Qubit[], Qubit, Int[]) => Unit),
oracle2 : ((Qubit[], Qubit, Int[]) => Unit : Adjoint)) : Unit {
AssertTwoOraclesAreEqual(Length(r) .. Length(r), oracle1(_, _, r), oracle2(_, _, r));
}
operation T15_Oracle_ProductFunction_Test () : Unit {
// cross-tests
// the mask for all 1's corresponds to Oracle_OddNumberOfOnes
mutable r = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let L = Length(r);
for (i in 2 .. L) {
AssertTwoOraclesAreEqual(i .. i, Oracle_ProductFunction(_, _, r[0 .. i - 1]), Oracle_OddNumberOfOnes_Reference);
}
// the mask with all 0's corresponds to Oracle_Zero
for (i in 0 .. L - 1) {
set r[i] = 0;
}
for (i in 2 .. L) {
AssertTwoOraclesAreEqual(i .. i, Oracle_ProductFunction(_, _, r[0 .. i - 1]), Oracle_Zero_Reference);
}
// the mask with only the K-th element set to 1 corresponds to Oracle_Kth_Qubit
for (i in 0 .. L - 1) {
set r[i] = 1;
AssertTwoOraclesAreEqual(L .. L, Oracle_ProductFunction(_, _, r), Oracle_Kth_Qubit_Reference(_, _, i));
set r[i] = 0;
}
set r = [1, 0, 1, 0, 1, 0];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference);
set r = [1, 0, 0, 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference);
set r = [0, 0, 1, 1, 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference);
}
operation T16_Oracle_ProductWithNegationFunction_Test () : Unit {
// cross-tests
// the mask for all 1's corresponds to Oracle_OddNumberOfOnes
mutable r = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let L = Length(r);
for (i in 2 .. L) {
AssertTwoOraclesAreEqual(i .. i, Oracle_ProductWithNegationFunction(_, _, r[0 .. i - 1]), Oracle_OddNumberOfOnes_Reference);
}
set r = [1, 0, 1, 0, 1, 0];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference);
set r = [1, 0, 0, 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference);
set r = [0, 0, 1, 1, 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference);
}
operation T17_Oracle_HammingWithPrefix_Test () : Unit {
mutable prefix = [1];
AssertTwoOraclesAreEqual(1 .. 10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix));
set prefix = [1, 0];
AssertTwoOraclesAreEqual(2 .. 10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix));
set prefix = [0, 0, 0];
AssertTwoOraclesAreEqual(3 .. 10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix));
}
operation T18_Oracle_MajorityFunction_Test () : Unit {
AssertTwoOraclesAreEqual(3 .. 3, Oracle_MajorityFunction, Oracle_MajorityFunction_Reference);
}
// ------------------------------------------------------
operation T21_BV_StatePrep_Test () : Unit {
for (N in 1 .. 10) {
using (qs = Qubit[N + 1]) {
// apply operation that needs to be tested
BV_StatePrep(qs[0 .. N - 1], qs[N]);
// apply adjoint reference operation
Adjoint BV_StatePrep_Reference(qs[0 .. N - 1], qs[N]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
}
// ------------------------------------------------------
operation T11_Oracle_Zero_Test () : ()
{
body
{
AssertTwoOraclesAreEqual(1..10, Oracle_Zero, Oracle_Zero_Reference);
}
}
// ------------------------------------------------------
operation T12_Oracle_One_Test () : ()
{
body
{
AssertTwoOraclesAreEqual(1..10, Oracle_One, Oracle_One_Reference);
}
}
// ------------------------------------------------------
operation T13_Oracle_Kth_Qubit_Test () : ()
{
body
{
let maxQ = 6;
// loop over index of the qubit to be used
for (k in 0..maxQ-1) {
// number of qubits to try is from k+1 to 6
AssertTwoOraclesAreEqual(k+1..maxQ, Oracle_Kth_Qubit(_, _, k), Oracle_Kth_Qubit_Reference(_, _, k));
}
}
}
// ------------------------------------------------------
operation T14_Oracle_OddNumberOfOnes_Test () : ()
{
body
{
// cross-test: for 1 qubit it's the same as Kth_Qubit for k = 0
AssertTwoOraclesAreEqual(1..1, Oracle_OddNumberOfOnes, Oracle_Kth_Qubit_Reference(_, _, 0));
AssertTwoOraclesAreEqual(1..10, Oracle_OddNumberOfOnes, Oracle_OddNumberOfOnes_Reference);
}
}
// ------------------------------------------------------
operation AssertTwoOraclesWithIntAreEqual (r : Int[],
oracle1 : ((Qubit[], Qubit, Int[]) => ()),
oracle2 : ((Qubit[], Qubit, Int[]) => () : Adjoint)) : ()
{
body
{
AssertTwoOraclesAreEqual(Length(r)..Length(r), oracle1(_, _, r), oracle2(_, _, r));
}
}
operation T15_Oracle_ProductFunction_Test () : ()
{
body
{
// cross-tests
// the mask for all 1's corresponds to Oracle_OddNumberOfOnes
mutable r = [1; 1; 1; 1; 1; 1; 1; 1; 1; 1];
let L = Length(r);
for (i in 2..L) {
AssertTwoOraclesAreEqual(i..i, Oracle_ProductFunction(_, _, r[0..i-1]), Oracle_OddNumberOfOnes_Reference);
}
// the mask with all 0's corresponds to Oracle_Zero
for (i in 0..L-1) {
set r[i] = 0;
}
for (i in 2..L) {
AssertTwoOraclesAreEqual(i..i, Oracle_ProductFunction(_, _, r[0..i-1]), Oracle_Zero_Reference);
}
// the mask with only the K-th element set to 1 corresponds to Oracle_Kth_Qubit
for (i in 0..L-1) {
set r[i] = 1;
AssertTwoOraclesAreEqual(L..L, Oracle_ProductFunction(_, _, r), Oracle_Kth_Qubit_Reference(_, _, i));
set r[i] = 0;
}
set r = [1; 0; 1; 0; 1; 0];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference);
set r = [1; 0; 0; 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference);
set r = [0; 0; 1; 1; 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference);
}
}
operation T16_Oracle_ProductWithNegationFunction_Test () : ()
{
body
{
// cross-tests
// the mask for all 1's corresponds to Oracle_OddNumberOfOnes
mutable r = [1; 1; 1; 1; 1; 1; 1; 1; 1; 1];
let L = Length(r);
for (i in 2..L) {
AssertTwoOraclesAreEqual(i..i, Oracle_ProductWithNegationFunction(_, _, r[0..i-1]), Oracle_OddNumberOfOnes_Reference);
}
set r = [1; 0; 1; 0; 1; 0];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference);
set r = [1; 0; 0; 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference);
set r = [0; 0; 1; 1; 1];
AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference);
}
}
operation T17_Oracle_HammingWithPrefix_Test () : ()
{
body
{
mutable prefix = [1];
AssertTwoOraclesAreEqual(1..10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix));
set prefix = [1; 0];
AssertTwoOraclesAreEqual(2..10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix));
set prefix = [0; 0; 0];
AssertTwoOraclesAreEqual(3..10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix));
}
}
operation T18_Oracle_MajorityFunction_Test () : ()
{
body
{
AssertTwoOraclesAreEqual(3..3, Oracle_MajorityFunction, Oracle_MajorityFunction_Reference);
}
}
// ------------------------------------------------------
operation T21_BV_StatePrep_Test () : ()
{
body
{
for (N in 1..10) {
using (qs = Qubit[N+1])
{
// apply operation that needs to be tested
BV_StatePrep(qs[0..N-1], qs[N]);
// apply adjoint reference operation
(Adjoint BV_StatePrep_Reference)(qs[0..N-1], qs[N]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
}
}
// ------------------------------------------------------
function AssertOracleCallsCount<'T>(count: Int, oracle: 'T) : () { }
// ------------------------------------------------------
function ResetOracleCallsCount() : () { }
function AssertOracleCallsCount<'T> (count : Int, oracle : 'T) : Unit { }
// ------------------------------------------------------
function AssertIntArrayEqual (actual : Int[], expected : Int[], message : String) : () {
let n = Length(actual);
function ResetOracleCallsCount () : Unit { }
// ------------------------------------------------------
function AssertIntArrayEqual (actual : Int[], expected : Int[], message : String) : Unit {
let n = Length(actual);
if (n != Length(expected)) {
fail message;
}
for (idx in 0..(n-1)) {
if( actual[idx] != expected[idx] ) {
for (idx in 0 .. n - 1) {
if (actual[idx] != expected[idx]) {
fail message;
}
}
}
}
// ------------------------------------------------------
function IntArrFromPositiveInt (n : Int, bits : Int) : Int[] {
let rbool = BoolArrFromPositiveInt(n, bits);
mutable r = new Int[bits];
for (i in 0..bits-1) {
for (i in 0 .. bits - 1) {
if (rbool[i]) {
set r[i] = 1;
}
}
return r;
}
// ------------------------------------------------------
operation AssertBVAlgorithmWorks (r : Int[]) : ()
{
body
{
let oracle = Oracle_ProductFunction_Reference(_, _, r);
AssertIntArrayEqual(BV_Algorithm(Length(r), oracle), r, "Bernstein-Vazirani algorithm failed");
AssertOracleCallsCount(1, oracle);
}
operation AssertBVAlgorithmWorks (r : Int[]) : Unit {
let oracle = Oracle_ProductFunction_Reference(_, _, r);
AssertIntArrayEqual(BV_Algorithm(Length(r), oracle), r, "Bernstein-Vazirani algorithm failed");
AssertOracleCallsCount(1, oracle);
}
operation T22_BV_Algorithm_Test () : ()
{
body
{
ResetOracleCallsCount();
// test BV the way we suggest the learner to test it:
// apply the algorithm to reference oracles and check that the output is as expected
for (bits in 1..4) {
for (n in 0..2^bits-1) {
let r = IntArrFromPositiveInt(n, bits);
AssertBVAlgorithmWorks(r);
}
operation T22_BV_Algorithm_Test () : Unit {
ResetOracleCallsCount();
// test BV the way we suggest the learner to test it:
// apply the algorithm to reference oracles and check that the output is as expected
for (bits in 1 .. 4) {
for (n in 0 .. 2 ^ bits - 1) {
let r = IntArrFromPositiveInt(n, bits);
AssertBVAlgorithmWorks(r);
}
AssertBVAlgorithmWorks([1; 1; 1; 0; 0]);
AssertBVAlgorithmWorks([1; 0; 1; 0; 1; 0]);
}
AssertBVAlgorithmWorks([1, 1, 1, 0, 0]);
AssertBVAlgorithmWorks([1, 0, 1, 0, 1, 0]);
}
// ------------------------------------------------------
operation AssertDJAlgorithmWorks(oracle: ((Qubit[], Qubit) => ()), expected : Bool, msg: String) : ()
{
body
{
AssertBoolEqual(DJ_Algorithm(4, oracle), expected, msg);
AssertOracleCallsCount(1, oracle);
}
operation AssertDJAlgorithmWorks (oracle : ((Qubit[], Qubit) => Unit), expected : Bool, msg : String) : Unit {
AssertBoolEqual(DJ_Algorithm(4, oracle), expected, msg);
AssertOracleCallsCount(1, oracle);
}
operation T31_DJ_Algorithm_Test () : Unit {
operation T31_DJ_Algorithm_Test () : ()
{
body
{
ResetOracleCallsCount();
// test DJ the way we suggest the learner to test it:
// apply the algorithm to reference oracles and check that the output is as expected
AssertBoolEqual(DJ_Algorithm(4, Oracle_Zero_Reference), true, "f(x) = 0 not identified as constant");
AssertBoolEqual(DJ_Algorithm(4, Oracle_One_Reference), true, "f(x) = 1 not identified as constant");
AssertBoolEqual(DJ_Algorithm(4, Oracle_Kth_Qubit_Reference(_, _, 1)), false, "f(x) = x_k not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_OddNumberOfOnes_Reference), false, "f(x) = sum of x_i not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_ProductFunction_Reference(_, _, [1; 0; 1; 1])), false, "f(x) = sum of r_i x_i not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_ProductWithNegationFunction_Reference(_, _, [1; 0; 1; 1])), false, "f(x) = sum of r_i x_i + (1 - r_i)(1 - x_i) not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_HammingWithPrefix_Reference(_, _, [0; 1])), false, "f(x) = sum of x_i + 1 if prefix equals given not identified as balanced");
AssertBoolEqual(DJ_Algorithm(3, Oracle_MajorityFunction_Reference), false, "f(x) = majority function not identified as balanced");
}
ResetOracleCallsCount();
// test DJ the way we suggest the learner to test it:
// apply the algorithm to reference oracles and check that the output is as expected
AssertBoolEqual(DJ_Algorithm(4, Oracle_Zero_Reference), true, "f(x) = 0 not identified as constant");
AssertBoolEqual(DJ_Algorithm(4, Oracle_One_Reference), true, "f(x) = 1 not identified as constant");
AssertBoolEqual(DJ_Algorithm(4, Oracle_Kth_Qubit_Reference(_, _, 1)), false, "f(x) = x_k not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_OddNumberOfOnes_Reference), false, "f(x) = sum of x_i not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_ProductFunction_Reference(_, _, [1, 0, 1, 1])), false, "f(x) = sum of r_i x_i not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_ProductWithNegationFunction_Reference(_, _, [1, 0, 1, 1])), false, "f(x) = sum of r_i x_i + (1 - r_i)(1 - x_i) not identified as balanced");
AssertBoolEqual(DJ_Algorithm(4, Oracle_HammingWithPrefix_Reference(_, _, [0, 1])), false, "f(x) = sum of x_i + 1 if prefix equals given not identified as balanced");
AssertBoolEqual(DJ_Algorithm(3, Oracle_MajorityFunction_Reference), false, "f(x) = majority function not identified as balanced");
}
// ------------------------------------------------------
operation AssertNonameAlgorithmWorks (r : Int[]) : ()
{
body
{
let givenOracle = Oracle_ProductWithNegationFunction_Reference(_, _, r);
let res = Noname_Algorithm(Length(r), givenOracle);
// check that the oracle was called once (later it will be called again by test harness)
AssertOracleCallsCount(1, givenOracle);
// check that the oracle obtained from r
// is equivalent to the oracle obtained from return value
AssertIntEqual(Length(res), Length(r), "Returned bit vector must have the same length as the oracle input.");
let resOracle = Oracle_ProductWithNegationFunction_Reference(_, _, res);
AssertTwoOraclesAreEqual(Length(r)..Length(r), givenOracle, resOracle);
}
operation AssertNonameAlgorithmWorks (r : Int[]) : Unit {
let givenOracle = Oracle_ProductWithNegationFunction_Reference(_, _, r);
let res = Noname_Algorithm(Length(r), givenOracle);
// check that the oracle was called once (later it will be called again by test harness)
AssertOracleCallsCount(1, givenOracle);
// check that the oracle obtained from r
// is equivalent to the oracle obtained from return value
AssertIntEqual(Length(res), Length(r), "Returned bit vector must have the same length as the oracle input.");
let resOracle = Oracle_ProductWithNegationFunction_Reference(_, _, res);
AssertTwoOraclesAreEqual(Length(r) .. Length(r), givenOracle, resOracle);
}
operation CallNonameAlgoOnInt (n : Int, bits : Int) : ()
{
body
{
let r = IntArrFromPositiveInt(n, bits);
AssertNonameAlgorithmWorks(r);
}
operation CallNonameAlgoOnInt (n : Int, bits : Int) : Unit {
let r = IntArrFromPositiveInt(n, bits);
AssertNonameAlgorithmWorks(r);
}
operation T41_Noname_Algorithm_Test () : ()
{
body
{
ResetOracleCallsCount();
// apply the algorithm to reference oracles and check that the output is as expected
// test all bit vectors of length 1..4
for (bits in 1..4) {
for (n in 0..2^bits-1) {
CallNonameAlgoOnInt(n, bits);
}
operation T41_Noname_Algorithm_Test () : Unit {
ResetOracleCallsCount();
// apply the algorithm to reference oracles and check that the output is as expected
// test all bit vectors of length 1..4
for (bits in 1 .. 4) {
for (n in 0 .. 2 ^ bits - 1) {
CallNonameAlgoOnInt(n, bits);
}
// and a couple of random ones
AssertNonameAlgorithmWorks([1; 1; 1; 0; 0]);
AssertNonameAlgorithmWorks([1; 0; 1; 0; 1; 0]);
}
// and a couple of random ones
AssertNonameAlgorithmWorks([1, 1, 1, 0, 0]);
AssertNonameAlgorithmWorks([1, 0, 1, 0, 1, 0]);
}
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.GroversAlgorithm</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,111 +1,114 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.GroversAlgorithm
{
namespace Quantum.Kata.GroversAlgorithm {
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Part I. Oracles for Grover's Search
//////////////////////////////////////////////////////////////////
// Task 1.1. The |11...1〉 oracle
operation Oracle_AllOnes_Reference (queryRegister: Qubit[], target : Qubit) : ()
{
body
{
(Controlled X)(queryRegister, target);
operation Oracle_AllOnes_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
body (...) {
Controlled X(queryRegister, target);
}
adjoint auto;
adjoint invert;
}
// Task 1.2. The |1010...〉 oracle
operation Oracle_AlternatingBits_Reference (queryRegister: Qubit[], target : Qubit) : ()
{
body
{
// flip the bits in odd (0-based positions),
operation Oracle_AlternatingBits_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
body (...) {
// flip the bits in odd (0-based positions),
// so that the condition for flipping the state of the target qubit is "query register is in 1...1 state"
FlipOddPositionBits_Reference(queryRegister);
(Controlled X)(queryRegister, target);
(Adjoint FlipOddPositionBits_Reference)(queryRegister);
Controlled X(queryRegister, target);
Adjoint FlipOddPositionBits_Reference(queryRegister);
}
adjoint auto;
adjoint invert;
}
operation FlipOddPositionBits_Reference (register : Qubit[]) : ()
{
body
{
for (i in 0..Length(register) - 1)
{
if (i % 2 == 1)
{
operation FlipOddPositionBits_Reference (register : Qubit[]) : Unit {
body (...) {
for (i in 0 .. Length(register) - 1) {
if (i % 2 == 1) {
X(register[i]);
}
}
}
adjoint auto;
adjoint invert;
}
// Task 1.3. Arbitrary bit pattern oracle
operation Oracle_ArbitraryPattern_Reference (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : ()
{
body
{
operation Oracle_ArbitraryPattern_Reference (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : Unit {
body (...) {
(ControlledOnBitString(pattern, X))(queryRegister, target);
}
adjoint auto;
adjoint invert;
}
// Task 1.4*. Oracle converter
operation OracleConverterImpl_Reference (markingOracle : ((Qubit[], Qubit) => () : Adjoint), register : Qubit[]) : ()
{
body
{
using (ancillae = Qubit[1])
{
operation OracleConverterImpl_Reference (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint), register : Qubit[]) : Unit {
body (...) {
using (ancillae = Qubit[1]) {
let target = ancillae[0];
// Put the target into the |-〉 state
X(target);
H(target);
// Apply the marking oracle; since the target is in the |-〉 state,
// flipping the target if the register satisfies the oracle condition will apply a -1 factor to the state
markingOracle(register, target);
// Put the target back into |0〉 so we can return it
H(target);
X(target);
}
}
adjoint auto;
adjoint invert;
}
function OracleConverter_Reference (markingOracle : ((Qubit[], Qubit) => () : Adjoint)) : ((Qubit[]) => () : Adjoint)
{
function OracleConverter_Reference (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint)) : (Qubit[] => Unit : Adjoint) {
return OracleConverterImpl_Reference(markingOracle, _);
}
//////////////////////////////////////////////////////////////////
// Part II. The Grover iteration
//////////////////////////////////////////////////////////////////
// Task 2.1. The Hadamard transform
operation HadamardTransform_Reference (register: Qubit[]) : ()
{
body
{
operation HadamardTransform_Reference (register : Qubit[]) : Unit {
body (...) {
ApplyToEachA(H, register);
// ApplyToEach is a library routine that is equivalent to the following code:
@ -114,69 +117,71 @@ namespace Quantum.Kata.GroversAlgorithm
// H(register[idxQubit]);
// }
}
adjoint auto;
adjoint invert;
}
// Task 2.2. Conditional phase flip
operation ConditionalPhaseFlip_Reference (register : Qubit[]) : ()
{
body
{
operation ConditionalPhaseFlip_Reference (register : Qubit[]) : Unit {
body (...) {
// Define a marking oracle which detects an all zero state
let allZerosOracle = Oracle_ArbitraryPattern_Reference(_, _, new Bool[Length(register)]);
// Convert it into a phase-flip oracle and apply it
let flipOracle = OracleConverter_Reference(allZerosOracle);
flipOracle(register);
}
adjoint self;
}
operation PhaseFlip_ControlledZ (register : Qubit[]) : ()
{
body
{
operation PhaseFlip_ControlledZ (register : Qubit[]) : Unit {
body (...) {
// Alternative solution, described at https://quantumcomputing.stackexchange.com/questions/4268/how-to-construct-the-inversion-about-the-mean-operator/4269#4269
ApplyToEachA(X, register);
(Controlled Z)(Most(register), Tail(register));
Controlled Z(Most(register), Tail(register));
ApplyToEachA(X, register);
}
adjoint self;
}
// Task 2.3. The Grover iteration
operation GroverIteration_Reference (register : Qubit[], oracle : ((Qubit[]) => () : Adjoint)) : ()
{
body
{
operation GroverIteration_Reference (register : Qubit[], oracle : (Qubit[] => Unit : Adjoint)) : Unit {
body (...) {
oracle(register);
HadamardTransform_Reference(register);
ConditionalPhaseFlip_Reference(register);
HadamardTransform_Reference(register);
}
adjoint auto;
adjoint invert;
}
//////////////////////////////////////////////////////////////////
// Part III. Putting it all together: Grover's search algorithm
//////////////////////////////////////////////////////////////////
// Task 3.1. Grover's search
operation GroversSearch_Reference (register : Qubit[], oracle : ((Qubit[], Qubit) => () : Adjoint), iterations : Int) : ()
{
body
{
operation GroversSearch_Reference (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint), iterations : Int) : Unit {
body (...) {
let phaseOracle = OracleConverter_Reference(oracle);
HadamardTransform_Reference(register);
for (i in 1..iterations)
{
for (i in 1 .. iterations) {
GroverIteration_Reference(register, phaseOracle);
}
}
adjoint auto;
adjoint invert;
}
}

Просмотреть файл

@ -1,60 +1,62 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.GroversAlgorithm
{
namespace Quantum.Kata.GroversAlgorithm {
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// The "Grover's Search" quantum kata is a series of exercises designed
// The "Grover's Search" quantum kata is a series of exercises designed
// to get you familiar with Grover's search algorithm.
// It covers the following topics:
// - writing oracles for Grover's search,
// - performing steps of the algorithm, and
// - putting it all together: Grover's search algorithm.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//
// Within each section, tasks are given in approximate order of increasing difficulty;
// harder ones are marked with asterisks.
// Within each section, tasks are given in approximate order of increasing difficulty;
// harder ones are marked with asterisks.
//////////////////////////////////////////////////////////////////
// Part I. Oracles for Grover's Search
//////////////////////////////////////////////////////////////////
// Task 1.1. The |11...1〉 oracle
// Inputs:
// 1) N qubits in an arbitrary state |x⟩ (input/query register)
// 2) a qubit in an arbitrary state |y⟩ (target qubit)
// Goal: Flip the state of the target qubit (i.e., apply an X gate to it)
// Goal: Flip the state of the target qubit (i.e., apply an X gate to it)
// if the query register is in the |11...1⟩ state,
// and leave it unchanged if the query register is in any other state.
// Leave the query register in the same state it started in.
// Example:
// Example:
// If the query register is in state |00...0〉, leave the target qubit unchanged.
// If the query register is in state |10...0〉, leave the target qubit unchanged.
// If the query register is in state |11...1〉, flip the target qubit.
// If the query register is in state (|00...0〉 + |11...1〉) / sqrt(2), and the target is in state |0〉,
// the joint state of the query register and the target qubit should be (|00...00〉 + |11...11〉) / sqrt(2).
operation Oracle_AllOnes (queryRegister : Qubit[], target : Qubit) : ()
{
body
{
operation Oracle_AllOnes (queryRegister : Qubit[], target : Qubit) : Unit {
body (...) {
// ...
}
}
adjoint self;
}
// Task 1.2. The |1010...〉 oracle
// Inputs:
// 1) N qubits in an arbitrary state |x⟩ (input/query register)
@ -63,132 +65,135 @@ namespace Quantum.Kata.GroversAlgorithm
// that is, the state with alternating 1 and 0 values, with any number of qubits in the register.
// Leave the state of the target qubit unchanged if the query register is in any other state.
// Leave the query register in the same state it started in.
// Example:
// Example:
// If the register is in state |0000000〉, leave the target qubit unchanged.
// If the register is in state |10101〉, flip the target qubit.
operation Oracle_AlternatingBits (queryRegister : Qubit[], target : Qubit) : ()
{
body
{
operation Oracle_AlternatingBits (queryRegister : Qubit[], target : Qubit) : Unit {
body (...) {
// ...
}
adjoint self;
}
// Task 1.3. Arbitrary bit pattern oracle
// Inputs:
// 1) N qubits in an arbitrary state |x⟩ (input/query register)
// 2) a qubit in an arbitrary state |y⟩ (target qubit)
// 3) a bit pattern of length N represented as Bool[]
// Goal: Flip the state of the target qubit if the query register is in the state described by the given bit pattern
// (true represents qubit state One, and false represents Zero).
// (true represents qubit state One, and false represents Zero).
// Leave the state of the target qubit unchanged if the query register is in any other state.
// Leave the query register in the same state it started in.
// Example:
// If the bit patterns is [true; false], you need to flip the target qubit if and only if the qubits are in the |10⟩ state.
operation Oracle_ArbitraryPattern (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : ()
{
body
{
// Example:
// If the bit patterns is [true, false], you need to flip the target qubit if and only if the qubits are in the |10⟩ state.
operation Oracle_ArbitraryPattern (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : Unit {
body (...) {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(queryRegister), Length(pattern), "Arrays should have the same length");
// ...
}
adjoint self;
}
// Task 1.4*. Oracle converter
// Input: A marking oracle: an oracle that takes a register and a target qubit and
// Input: A marking oracle: an oracle that takes a register and a target qubit and
// flips the target qubit if the register satisfies a certain condition
// Output: A phase-flipping oracle: an oracle that takes a register and
// Output: A phase-flipping oracle: an oracle that takes a register and
// flips the phase of the register if it satisfies this condition
//
// Note: Grover's algorithm relies on the search condition implemented as a phase-flipping oracle,
// but it is often easier to write a marking oracle for a given condition. This transformation
// allows to convert one type of oracle into the other. The transformation is described at
// but it is often easier to write a marking oracle for a given condition. This transformation
// allows to convert one type of oracle into the other. The transformation is described at
// https://en.wikipedia.org/wiki/Grover%27s_algorithm, section "Description of Uω".
function OracleConverter (markingOracle : ((Qubit[], Qubit) => () : Adjoint)) : (Qubit[] => () : Adjoint)
{
// Hint: Remember that you can define auxiliary operations.
function OracleConverter (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint)) : (Qubit[] => Unit : Adjoint) {
// Hint: Remember that you can define auxiliary operations.
// ...
// Currently this function returns a no-op operation for the sake of being able to compile the code.
// You will need to remove ApplyToEachA and return your own oracle instead.
// You will need to remove ApplyToEachA and return your own oracle instead.
return ApplyToEachA(I, _);
}
//////////////////////////////////////////////////////////////////
// Part II. The Grover iteration
//////////////////////////////////////////////////////////////////
// Task 2.1. The Hadamard transform
// Input: A register of N qubits in an arbitrary state
// Goal: Apply the Hadamard transform to each of the qubits in the register.
//
// Note: If the register started in the |0...0〉 state, this operation
//
// Note: If the register started in the |0...0〉 state, this operation
// will prepare an equal superposition of all 2^N basis states.
operation HadamardTransform (register : Qubit[]) : ()
{
body
{
operation HadamardTransform (register : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 2.2. Conditional phase flip
// Input: A register of N qubits in an arbitrary state.
// Goal: Flip the sign of the state of the register if it is not in the |0...0〉 state.
// Example:
// If the register is in state |0...0〉, leave it unchanged.
// If the register is in any other basis state, multiply its phase by -1.
// Example:
// If the register is in state |0...0〉, leave it unchanged.
// If the register is in any other basis state, multiply its phase by -1.
// Note: This operation implements operator 2|0...0〉⟨0...0| - I.
operation ConditionalPhaseFlip (register : Qubit[]) : ()
{
body
{
// Hint 1: Note that quantum states are defined up to a global phase.
// Thus the state obtained as a result of this operation is the same
// as the state obtained by flipping the sign of only the |0...0〉 state.
// Hint 2: You can use the same trick as in the oracle converter task.
operation ConditionalPhaseFlip (register : Qubit[]) : Unit {
body (...) {
// Hint 1: Note that quantum states are defined up to a global phase.
// Thus the state obtained as a result of this operation is the same
// as the state obtained by flipping the sign of only the |0...0〉 state.
// Hint 2: You can use the same trick as in the oracle converter task.
// ...
}
adjoint auto;
adjoint invert;
}
// Task 2.3. The Grover iteration
// Inputs:
// 1) N qubits in an arbitrary state |x⟩ (input/query register)
// 2) a phase-flipping oracle that takes an N-qubit register and flips
// 2) a phase-flipping oracle that takes an N-qubit register and flips
// the phase of the state if the register is in the desired state.
// Goal: Perform one Grover iteration.
operation GroverIteration (register : Qubit[], oracle : (Qubit[] => () : Adjoint)) : ()
{
body
{
operation GroverIteration (register : Qubit[], oracle : (Qubit[] => Unit : Adjoint)) : Unit {
body (...) {
// Hint: A Grover iteration consists of 4 steps:
// 1) apply the oracle
// 2) apply the Hadamard transform
// 3) perform a conditional phase shift
// 4) apply the Hadamard transform again
// ...
}
adjoint auto;
adjoint invert;
}
//////////////////////////////////////////////////////////////////
// Part III. Putting it all together: Grover's search algorithm
//////////////////////////////////////////////////////////////////
// Task 3.1. Grover's search
// Inputs:
// 1) N qubits in the |0...0〉 state,
@ -199,22 +204,16 @@ namespace Quantum.Kata.GroversAlgorithm
//
// Note: The number of iterations is passed as a parameter because it is defined by the nature of the problem
// and is easier to configure/calculate outside the search algorithm itself (for example, in the driver).
operation GroversSearch (register : Qubit[], oracle : ((Qubit[], Qubit) => () : Adjoint), iterations : Int) : ()
{
body
{
operation GroversSearch (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint), iterations : Int) : Unit {
// ...
}
}
// Task 3.2. Using Grover's search
// Goal: Use your implementation of Grover's algorithm from task 3.1 and the oracles from part 1
// to find the marked elements of the search space.
// This task is not covered by a test and allows you to experiment with running the algorithm.
operation E2E_GroversSearch_Test () : ()
{
body
{
operation E2E_GroversSearch_Test () : Unit {
// Hint 1: To check whether the algorithm found the correct answer (i.e., an answer marked as 1 by the oracle),
// you can apply the oracle once more to the register after you've measured it and an ancilla qubit,
// which will calculate the function of the answer found by the algorithm.
@ -225,7 +224,6 @@ namespace Quantum.Kata.GroversAlgorithm
// Hint 3: You can use the Message function to write the results to the console.
// ...
}
}
}

Просмотреть файл

@ -1,140 +1,115 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.GroversAlgorithm
{
namespace Quantum.Kata.GroversAlgorithm {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Testing;
// ------------------------------------------------------
// helper wrapper to represent oracle operation on input and output registers as an operation on an array of qubits
operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit) => () : Adjoint), qs : Qubit[]) : ()
{
body
{
operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit) => Unit : Adjoint), qs : Qubit[]) : Unit {
body (...) {
op(Most(qs), Tail(qs));
}
adjoint auto;
adjoint invert;
}
// ------------------------------------------------------
// helper wrapper to test for operation equality on various register sizes
operation AssertRegisterOperationsEqual (testOp : ((Qubit[]) => ()), refOp : ((Qubit[]) => () : Adjoint)) : ()
{
body
{
for (n in 2..10) {
AssertOperationsEqualReferenced(testOp, refOp, n);
}
operation AssertRegisterOperationsEqual (testOp : (Qubit[] => Unit), refOp : (Qubit[] => Unit : Adjoint)) : Unit {
for (n in 2 .. 10) {
AssertOperationsEqualReferenced(testOp, refOp, n);
}
}
// ------------------------------------------------------
operation T11_Oracle_AllOnes_Test () : ()
{
body
{
let testOp = QubitArrayWrapperOperation(Oracle_AllOnes, _);
let refOp = QubitArrayWrapperOperation(Oracle_AllOnes_Reference, _);
AssertRegisterOperationsEqual(testOp, refOp);
}
operation T11_Oracle_AllOnes_Test () : Unit {
let testOp = QubitArrayWrapperOperation(Oracle_AllOnes, _);
let refOp = QubitArrayWrapperOperation(Oracle_AllOnes_Reference, _);
AssertRegisterOperationsEqual(testOp, refOp);
}
// ------------------------------------------------------
operation T12_Oracle_AlternatingBits_Test () : ()
{
body
{
let testOp = QubitArrayWrapperOperation(Oracle_AlternatingBits, _);
let refOp = QubitArrayWrapperOperation(Oracle_AlternatingBits_Reference, _);
AssertRegisterOperationsEqual(testOp, refOp);
}
operation T12_Oracle_AlternatingBits_Test () : Unit {
let testOp = QubitArrayWrapperOperation(Oracle_AlternatingBits, _);
let refOp = QubitArrayWrapperOperation(Oracle_AlternatingBits_Reference, _);
AssertRegisterOperationsEqual(testOp, refOp);
}
// ------------------------------------------------------
operation T13_Oracle_ArbitraryPattern_Test () : ()
{
body
{
for (n in 2..10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let testOp = QubitArrayWrapperOperation(Oracle_ArbitraryPattern(_, _, pattern), _);
let refOp = QubitArrayWrapperOperation(Oracle_ArbitraryPattern_Reference(_, _, pattern), _);
AssertOperationsEqualReferenced(testOp, refOp, n+1);
}
operation T13_Oracle_ArbitraryPattern_Test () : Unit {
for (n in 2 .. 10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let testOp = QubitArrayWrapperOperation(Oracle_ArbitraryPattern(_, _, pattern), _);
let refOp = QubitArrayWrapperOperation(Oracle_ArbitraryPattern_Reference(_, _, pattern), _);
AssertOperationsEqualReferenced(testOp, refOp, n + 1);
}
}
// ------------------------------------------------------
operation T14_OracleConverter_Test () : ()
{
body
{
for (n in 2..10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
let phaseOracleRef = OracleConverter_Reference(markingOracle);
let phaseOracleSol = OracleConverter(markingOracle);
AssertOperationsEqualReferenced(phaseOracleSol, phaseOracleRef, n);
}
operation T14_OracleConverter_Test () : Unit {
for (n in 2 .. 10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
let phaseOracleRef = OracleConverter_Reference(markingOracle);
let phaseOracleSol = OracleConverter(markingOracle);
AssertOperationsEqualReferenced(phaseOracleSol, phaseOracleRef, n);
}
}
// ------------------------------------------------------
operation T21_HadamardTransform_Test () : ()
{
body
{
AssertRegisterOperationsEqual(HadamardTransform, HadamardTransform_Reference);
}
operation T21_HadamardTransform_Test () : Unit {
AssertRegisterOperationsEqual(HadamardTransform, HadamardTransform_Reference);
}
// ------------------------------------------------------
operation T22_ConditionalPhaseFlip_Test () : ()
{
body
{
AssertRegisterOperationsEqual(ConditionalPhaseFlip, ConditionalPhaseFlip_Reference);
}
operation T22_ConditionalPhaseFlip_Test () : Unit {
AssertRegisterOperationsEqual(ConditionalPhaseFlip, ConditionalPhaseFlip_Reference);
}
// ------------------------------------------------------
operation T23_GroverIteration_Test () : ()
{
body
{
for (n in 2..10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
let flipOracle = OracleConverter_Reference(markingOracle);
let testOp = GroverIteration(_, flipOracle);
let refOp = GroverIteration_Reference(_, flipOracle);
AssertOperationsEqualReferenced(testOp, refOp, n);
}
operation T23_GroverIteration_Test () : Unit {
for (n in 2 .. 10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
let flipOracle = OracleConverter_Reference(markingOracle);
let testOp = GroverIteration(_, flipOracle);
let refOp = GroverIteration_Reference(_, flipOracle);
AssertOperationsEqualReferenced(testOp, refOp, n);
}
}
// ------------------------------------------------------
operation T31_GroversSearch_Test () : ()
{
body
{
for (n in 2..10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
let testOp = GroversSearch(_, markingOracle, 4);
let refOp = GroversSearch_Reference(_, markingOracle, 4);
AssertOperationsEqualReferenced(testOp, refOp, n);
}
operation T31_GroversSearch_Test () : Unit {
for (n in 2 .. 10) {
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
let testOp = GroversSearch(_, markingOracle, 4);
let refOp = GroversSearch_Reference(_, markingOracle, 4);
AssertOperationsEqualReferenced(testOp, refOp, n);
}
}
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.JointMeasurements</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,120 +1,103 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.JointMeasurements
{
namespace Quantum.Kata.JointMeasurements {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Math;
// Task 1. Single-qubit measurement
operation SingleQubitMeasurement_Reference (qs : Qubit[]) : Int
{
body
{
// Hint: use two single-qubit measurements
if (M(qs[0]) == M(qs[1])) {
return 0;
} else {
return 1;
}
operation SingleQubitMeasurement_Reference (qs : Qubit[]) : Int {
// Hint: use two single-qubit measurements
if (M(qs[0]) == M(qs[1])) {
return 0;
} else {
return 1;
}
}
// Task 2. Parity measurement
operation ParityMeasurement_Reference (qs : Qubit[]) : Int
{
body
{
if (Measure([PauliZ; PauliZ], qs) == Zero) {
return 0;
} else {
return 1;
}
operation ParityMeasurement_Reference (qs : Qubit[]) : Int {
if (Measure([PauliZ, PauliZ], qs) == Zero) {
return 0;
} else {
return 1;
}
}
// Task 3. |0000⟩ + |1111⟩ or |0011⟩ + |1100⟩ ?
operation GHZOrGHZWithX_Reference (qs : Qubit[]) : Int
{
body
{
if (Measure([PauliZ; PauliZ], qs[1..2]) == Zero) {
return 0;
} else {
return 1;
}
operation GHZOrGHZWithX_Reference (qs : Qubit[]) : Int {
if (Measure([PauliZ, PauliZ], qs[1 .. 2]) == Zero) {
return 0;
} else {
return 1;
}
}
// Task 4. |0..0⟩ + |1..1⟩ or W state ?
operation GHZOrWState_Reference (qs : Qubit[]) : Int
{
body
{
if (MeasureAllZ(qs) == Zero) {
return 0;
} else {
return 1;
}
operation GHZOrWState_Reference (qs : Qubit[]) : Int {
if (MeasureAllZ(qs) == Zero) {
return 0;
} else {
return 1;
}
}
// Task 5. Parity measurement in different basis
operation DifferentBasis_Reference (qs : Qubit[]) : Int
{
body
{
// The first state is a superposition of |++⟩ and |--⟩,
// the second one - of |+-⟩ and |-+⟩
if (Measure([PauliX; PauliX], qs) == Zero) {
return 0;
} else {
return 1;
}
operation DifferentBasis_Reference (qs : Qubit[]) : Int {
// The first state is a superposition of |++⟩ and |--⟩,
// the second one - of |+-⟩ and |-+⟩
if (Measure([PauliX, PauliX], qs) == Zero) {
return 0;
} else {
return 1;
}
}
// Task 6. Controlled X gate with |0⟩ target
operation ControlledX_Reference (qs : Qubit[]) : ()
{
body
{
H(qs[1]);
if (Measure([PauliZ; PauliZ], qs) == One) {
X(qs[1]);
}
operation ControlledX_Reference (qs : Qubit[]) : Unit {
H(qs[1]);
if (Measure([PauliZ, PauliZ], qs) == One) {
X(qs[1]);
}
}
// Task 7*. Controlled X gate with arbitrary target
operation ControlledX_General_Reference (qs : Qubit[]) : ()
{
body
{
operation ControlledX_General_Reference (qs : Qubit[]) : Unit {
body (...) {
// This implementation follows the description at https://arxiv.org/pdf/1201.5734.pdf.
// Note the parity notation used in the table of fixups in the paper
// Note the parity notation used in the table of fixups in the paper
// differs from the notation used in Q#.
using (ans = Qubit[1]) {
let c = qs[0];
let a = ans[0];
let t = qs[1];
H(a);
let p1 = MeasureAllZ([c; a]);
let p1 = MeasureAllZ([c, a]);
H(a);
H(t);
let p2 = MeasureAllZ([a; t]);
let p2 = MeasureAllZ([a, t]);
H(a);
H(t);
let m = M(a);
// apply fixups
if (p2 == One) {
Z(c);
@ -122,12 +105,15 @@ namespace Quantum.Kata.JointMeasurements
if (p1 != m) {
X(t);
}
// reset ancilla qubit
if (m == One) {
X(a);
}
}
}
adjoint self;
}
}

Просмотреть файл

@ -1,111 +1,97 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.JointMeasurements
{
namespace Quantum.Kata.JointMeasurements {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Joint Measurements" quantum kata is a series of exercises designed
// "Joint Measurements" quantum kata is a series of exercises designed
// to get you familiar with programming in Q#.
// It covers the joint parity measurements and using them for distinguishing quantum states
// It covers the joint parity measurements and using them for distinguishing quantum states
// or for performing multi-qubit gates.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// Task 1. Single-qubit measurement
// Input: Two qubits (stored in an array) which are guaranteed to be
// Input: Two qubits (stored in an array) which are guaranteed to be
// either in superposition of states |00⟩ and |11⟩
// or in superposition of states |01⟩ and |10⟩.
// Output: 0 if qubits were in the first superposition,
// 1 if they were in the second superposition.
// The state of the qubits at the end of the operation does not matter.
operation SingleQubitMeasurement (qs : Qubit[]) : Int
{
body
{
// Hint: Use two single-qubit measurements.
// ...
return -1;
}
operation SingleQubitMeasurement (qs : Qubit[]) : Int {
// Hint: Use two single-qubit measurements.
// ...
return -1;
}
// Task 2. Parity measurement
// Input: Two qubits (stored in an array) which are guaranteed to be
// Input: Two qubits (stored in an array) which are guaranteed to be
// either in superposition of states |00⟩ and |11⟩
// or in superposition of states |01⟩ and |10⟩.
// Output: 0 if qubits were in the first superposition,
// 1 if they were in the second superposition.
// The state of the qubits at the end of the operation should be the same as the starting state.
operation ParityMeasurement (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation ParityMeasurement (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 3. |0000⟩ + |1111⟩ or |0011⟩ + |1100⟩ ?
// Input: Four qubits (stored in an array) which are guaranteed to be
// Input: Four qubits (stored in an array) which are guaranteed to be
// either in superposition of states |0000⟩ and |1111⟩
// or in superposition of states |0011⟩ and |1100⟩.
// Output: 0 if qubits were in the first superposition,
// 1 if they were in the second superposition.
// The state of the qubits at the end of the operation should be the same as the starting state.
operation GHZOrGHZWithX (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation GHZOrGHZWithX (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 4. |0..0⟩ + |1..1⟩ or W state ?
// Input: An even number of qubits (stored in an array) which are guaranteed to be
// Input: An even number of qubits (stored in an array) which are guaranteed to be
// either in superposition of states |0..0⟩ and |1..1⟩
// or in W state ( https://en.wikipedia.org/wiki/W_state ).
// Output: 0 if qubits were in W state,
// 1 if they were in the second superposition.
// The state of the qubits at the end of the operation should be the same as the starting state.
operation GHZOrWState (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation GHZOrWState (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 5. Parity measurement in different basis
// Input: Two qubits (stored in an array) which are guaranteed to be
// Input: Two qubits (stored in an array) which are guaranteed to be
// either in superposition α|00⟩ + β|01⟩ + β|10⟩ + α|11⟩
// or in superposition α|00⟩ - β|01⟩ + β|10⟩ - α|11⟩.
// Output: 0 if qubits were in the first superposition,
// 1 if they were in the second superposition.
// The state of the qubits at the end of the operation should be the same as the starting state.
operation DifferentBasis (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation DifferentBasis (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 6. Controlled X gate with |0⟩ target
// Input: Two unentangled qubits (stored in an array of length 2).
// The first qubit will be in state |ψ⟩ = α |0⟩ + β |1⟩, the second - in state |0⟩
@ -113,26 +99,24 @@ namespace Quantum.Kata.JointMeasurements
// Goal: Change the two-qubit state to α |00⟩ + β |11⟩ using only single-qubit gates and joint measurements.
// Do not use two-qubit gates.
// You do not need to allocate extra qubits.
operation ControlledX (qs : Qubit[]) : ()
{
body
{
// ...
}
operation ControlledX (qs : Qubit[]) : Unit {
// ...
}
// Task 7*. Controlled X gate with arbitrary target
// Input: Two qubits (stored in an array of length 2) in an arbitrary
// Input: Two qubits (stored in an array of length 2) in an arbitrary
// two-qubit state α|00⟩ + β|01⟩ + γ|10⟩ + δ|11⟩.
// Goal: Change the two-qubit state to α|00⟩ + β|01⟩ + δ|10⟩ + γ|11⟩ using only single-qubit gates and joint measurements.
// Do not use two-qubit gates.
operation ControlledX_General (qs : Qubit[]) : ()
{
body
{
operation ControlledX_General (qs : Qubit[]) : Unit {
body (...) {
// Hint: You can use an extra qubit to perform this operation.
// ...
}
adjoint self;
}
}

Просмотреть файл

@ -1,227 +1,228 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.JointMeasurements
{
namespace Quantum.Kata.JointMeasurements {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Testing;
// "Framework" operation for testing multi-qubit tasks for distinguishing states of an array of qubits
// with Int return
operation DistinguishStates_MultiQubit (
Nqubit : Int,
Nstate : Int,
statePrep : ((Qubit[], Int, Double) => () : Adjoint),
testImpl : (Qubit[] => Int),
preserveState : Bool
) : ()
{
body
{
let nTotal = 100;
mutable nOk = 0;
using (qs = Qubit[Nqubit])
{
for (i in 1..nTotal)
{
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// get a random rotation angle to define the exact state of the qubits
let alpha = RandomReal(5) * PI();
// do state prep: convert |0...0⟩ to outcome with return equal to state
statePrep(qs, state, alpha);
operation DistinguishStates_MultiQubit (Nqubit : Int, Nstate : Int, statePrep : ((Qubit[], Int, Double) => Unit : Adjoint), testImpl : (Qubit[] => Int), preserveState : Bool) : Unit {
let nTotal = 100;
mutable nOk = 0;
// get the solution's answer and verify that it's a match
let ans = testImpl(qs);
if (ans == state) {
set nOk = nOk + 1;
}
if (preserveState) {
// check that the state of the qubit after the operation is unchanged
(Adjoint statePrep)(qs, state, alpha);
AssertAllZero(qs);
} else {
// we're not checking the state of the qubit after the operation
ResetAll(qs);
}
using (qs = Qubit[Nqubit]) {
for (i in 1 .. nTotal) {
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// get a random rotation angle to define the exact state of the qubits
let alpha = RandomReal(5) * PI();
// do state prep: convert |0...0⟩ to outcome with return equal to state
statePrep(qs, state, alpha);
// get the solution's answer and verify that it's a match
let ans = testImpl(qs);
if (ans == state) {
set nOk = nOk + 1;
}
if (preserveState) {
// check that the state of the qubit after the operation is unchanged
Adjoint statePrep(qs, state, alpha);
AssertAllZero(qs);
} else {
// we're not checking the state of the qubit after the operation
ResetAll(qs);
}
}
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
}
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
}
// ------------------------------------------------------
operation StatePrep_ParityMeasurement (qs : Qubit[], state : Int, alpha : Double) : () {
body {
operation StatePrep_ParityMeasurement (qs : Qubit[], state : Int, alpha : Double) : Unit {
body (...) {
// prep cos(alpha) * |0..0⟩ + sin(alpha) * |1..1⟩
Ry(2.0 * alpha, qs[0]);
for (i in 1..Length(qs)-1) {
for (i in 1 .. Length(qs) - 1) {
CNOT(qs[0], qs[i]);
}
if (state == 1) {
// flip the state of the last half of the qubits
for (i in 0..Length(qs)/2-1) {
for (i in 0 .. Length(qs) / 2 - 1) {
X(qs[i]);
}
}
}
adjoint auto;
}
// ------------------------------------------------------
operation T01_SingleQubitMeasurement_Test () : () {
body {
DistinguishStates_MultiQubit(2, 2, StatePrep_ParityMeasurement, SingleQubitMeasurement, false);
}
}
// ------------------------------------------------------
operation T02_ParityMeasurement_Test () : () {
body {
DistinguishStates_MultiQubit(2, 2, StatePrep_ParityMeasurement, ParityMeasurement, true);
}
adjoint invert;
}
// ------------------------------------------------------
operation T03_GHZOrGHZWithX_Test () : () {
body {
DistinguishStates_MultiQubit(4, 2, StatePrep_ParityMeasurement, GHZOrGHZWithX, true);
}
operation T01_SingleQubitMeasurement_Test () : Unit {
DistinguishStates_MultiQubit(2, 2, StatePrep_ParityMeasurement, SingleQubitMeasurement, false);
}
// ------------------------------------------------------
operation StatePrep_WState_Arbitrary (qs : Qubit[]) : ()
{
body
{
operation T02_ParityMeasurement_Test () : Unit {
DistinguishStates_MultiQubit(2, 2, StatePrep_ParityMeasurement, ParityMeasurement, true);
}
// ------------------------------------------------------
operation T03_GHZOrGHZWithX_Test () : Unit {
DistinguishStates_MultiQubit(4, 2, StatePrep_ParityMeasurement, GHZOrGHZWithX, true);
}
// ------------------------------------------------------
operation StatePrep_WState_Arbitrary (qs : Qubit[]) : Unit {
body (...) {
let N = Length(qs);
if (N == 1) {
// base case of recursion: |1⟩
X(qs[0]);
} else {
}
else {
// |W_N> = |0⟩|W_(N-1)> + |1⟩|0...0⟩
// do a rotation on the first qubit to split it into |0⟩ and |1⟩ with proper weights
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
let theta = ArcSin(1.0 / Sqrt(ToDouble(N)));
Ry(2.0 * theta, qs[0]);
// do a zero-controlled W-state generation for qubits 1..N-1
X(qs[0]);
(Controlled StatePrep_WState_Arbitrary)(qs[0..0], qs[1..N-1]);
Controlled StatePrep_WState_Arbitrary(qs[0 .. 0], qs[1 .. N - 1]);
X(qs[0]);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
operation StatePrep_GHZOrWState (qs : Qubit[], state : Int, alpha : Double) : () {
body {
operation StatePrep_GHZOrWState (qs : Qubit[], state : Int, alpha : Double) : Unit {
body (...) {
if (state == 0) {
StatePrep_ParityMeasurement(qs, 0, alpha);
} else {
StatePrep_WState_Arbitrary(qs);
}
}
adjoint auto;
adjoint invert;
}
operation T04_GHZOrWState_Test () : () {
body {
for (i in 1..5) {
DistinguishStates_MultiQubit(2*i, 2, StatePrep_GHZOrWState, GHZOrWState, true);
}
operation T04_GHZOrWState_Test () : Unit {
for (i in 1 .. 5) {
DistinguishStates_MultiQubit(2 * i, 2, StatePrep_GHZOrWState, GHZOrWState, true);
}
}
// ------------------------------------------------------
operation StatePrep_DifferentBasis (qs : Qubit[], state : Int, alpha : Double) : () {
body {
operation StatePrep_DifferentBasis (qs : Qubit[], state : Int, alpha : Double) : Unit {
body (...) {
// prep cos(alpha) * |00⟩ + sin(alpha) * |11⟩
Ry(2.0 * alpha, qs[0]);
CNOT(qs[0], qs[1]);
if (state == 1) {
X(qs[1]);
}
// convert to X basis
ApplyToEachA(H, qs);
}
adjoint auto;
adjoint invert;
}
operation T05_DifferentBasis_Test () : () {
body {
DistinguishStates_MultiQubit(2, 2, StatePrep_DifferentBasis, DifferentBasis, true);
}
operation T05_DifferentBasis_Test () : Unit {
DistinguishStates_MultiQubit(2, 2, StatePrep_DifferentBasis, DifferentBasis, true);
}
// ------------------------------------------------------
// prepare state |A⟩ = cos(α) * |0⟩ + sin(α) * |1⟩
operation StatePrep_A (alpha : Double, q : Qubit) : () {
body {
operation StatePrep_A (alpha : Double, q : Qubit) : Unit {
body (...) {
Ry(2.0 * alpha, q);
}
adjoint auto;
adjoint invert;
}
// ------------------------------------------------------
operation T06_ControlledX_Test () : ()
{
body
{
// Note that the way the problem is formulated, we can't just compare two unitaries,
// we need to create an input state |A⟩ and check that the output state is correct
using (qs = Qubit[2])
{
for (i in 0..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
// prepare A state
StatePrep_A(alpha, qs[0]);
// apply operation that needs to be tested
ControlledX(qs);
// apply adjoint reference operation and adjoint of state prep
CNOT(qs[0], qs[1]);
(Adjoint StatePrep_A)(alpha, qs[0]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
operation T06_ControlledX_Test () : Unit {
// Note that the way the problem is formulated, we can't just compare two unitaries,
// we need to create an input state |A⟩ and check that the output state is correct
using (qs = Qubit[2]) {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
// prepare A state
StatePrep_A(alpha, qs[0]);
// apply operation that needs to be tested
ControlledX(qs);
// apply adjoint reference operation and adjoint of state prep
CNOT(qs[0], qs[1]);
Adjoint StatePrep_A(alpha, qs[0]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
}
// ------------------------------------------------------
operation CNOTWrapper (qs : Qubit[]) : ()
{
body
{
operation CNOTWrapper (qs : Qubit[]) : Unit {
body (...) {
CNOT(qs[0], qs[1]);
}
adjoint self;
}
operation T07_ControlledX_General_Test () : ()
{
body
{
// In this task the gate is supposed to work on all inputs, so we can compare the unitary to CNOT.
AssertOperationsEqualReferenced(CNOTWrapper, ControlledX_General_Reference, 2);
AssertOperationsEqualReferenced(ControlledX_General, ControlledX_General_Reference, 2);
}
operation T07_ControlledX_General_Test () : Unit {
// In this task the gate is supposed to work on all inputs, so we can compare the unitary to CNOT.
AssertOperationsEqualReferenced(CNOTWrapper, ControlledX_General_Reference, 2);
AssertOperationsEqualReferenced(ControlledX_General, ControlledX_General_Reference, 2);
}
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.Measurements</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,132 +1,116 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.Measurements
{
namespace Quantum.Kata.Measurements {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Math;
//////////////////////////////////////////////////////////////////
// Part I. Single-Qubit Measurements
//////////////////////////////////////////////////////////////////
// Task 1.1. |0⟩ or |1⟩ ?
// Input: a qubit which is guaranteed to be in |0⟩ or |1⟩ state.
// Output: true if qubit was in |1⟩ state, or false if it was in |0⟩ state.
// The state of the qubit at the end of the operation does not matter.
operation IsQubitOne_Reference (q : Qubit) : Bool
{
body
{
let res = M(q);
return res == One;
}
operation IsQubitOne_Reference (q : Qubit) : Bool {
let res = M(q);
return res == One;
}
// Task 1.2. Set qubit to |0⟩ state
operation InitializeQubit_Reference (q : Qubit) : ()
{
body
{
if (M(q) == One) {
X(q);
}
// Note: this can be accomplished using Reset library operation.
// Reset(q);
operation InitializeQubit_Reference (q : Qubit) : Unit {
if (M(q) == One) {
X(q);
}
}
// Task 1.3. |+⟩ or |-⟩ ?
// Input: a qubit which is guaranteed to be in |+⟩ or |-⟩ state
// (|+⟩ = (|0⟩ + |1⟩) / sqrt(2), |-⟩ = (|0⟩ - |1⟩) / sqrt(2)).
// Output: true if qubit was in |+⟩ state, or false if it was in |-⟩ state.
// The state of the qubit at the end of the operation does not matter.
operation IsQubitPlus_Reference (q : Qubit) : Bool
{
body
{
H(q);
let res = M(q);
return res == Zero;
}
operation IsQubitPlus_Reference (q : Qubit) : Bool {
H(q);
let res = M(q);
return res == Zero;
}
// Task 1.4. |A⟩ or |B⟩ ?
// Inputs:
// 1) angle alpha, in radians, represented as Double
// 2) a qubit which is guaranteed to be in |A⟩ or |B⟩ state
// |A⟩ = cos(alpha) * |0⟩ + sin(alpha) * |1⟩,
// |A⟩ = cos(alpha) * |0⟩ + sin(alpha) * |1⟩,
// |B⟩ = - sin(alpha) * |0⟩ + cos(alpha) * |1⟩.
// Output: true if qubit was in |A⟩ state, or false if it was in |B⟩ state.
// The state of the qubit at the end of the operation does not matter.
operation IsQubitA_Reference (alpha : Double, q : Qubit) : Bool
{
body
{
// |0⟩ is converted into |A⟩ and |1⟩ into |B⟩ by Ry(2.0 * alpha)
// so |A⟩ is converted into |0⟩ by the opposite rotation
Ry(- 2.0 * alpha, q);
let res = M(q);
return res == Zero;
}
operation IsQubitA_Reference (alpha : Double, q : Qubit) : Bool {
// |0⟩ is converted into |A⟩ and |1⟩ into |B⟩ by Ry(2.0 * alpha)
// so |A⟩ is converted into |0⟩ by the opposite rotation
Ry(-2.0 * alpha, q);
let res = M(q);
return res == Zero;
}
// Task 1.5. |00⟩ or |11⟩ ?
// Input: two qubits (stored in an array) which are guaranteed to be in |00⟩ or |11⟩ state.
// Output: 0 if qubits were in |00⟩ state,
// 1 if they were in |11⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation ZeroZeroOrOneOne_Reference (qs : Qubit[]) : Int
{
body
{
// it's enough to do one measurement on any qubit
let res = M(qs[0]);
if (res == Zero) {
return 0;
} else {
return 1;
}
operation ZeroZeroOrOneOne_Reference (qs : Qubit[]) : Int {
// it's enough to do one measurement on any qubit
let res = M(qs[0]);
if (res == Zero) {
return 0;
} else {
return 1;
}
}
// Task 1.6. Distinguish four basis states
// Input: two qubits (stored in an array) which are guaranteed to be
// Input: two qubits (stored in an array) which are guaranteed to be
// in one of the four basis states (|00⟩, |01⟩, |10⟩ or |11⟩).
// Output: 0 if qubits were in |00⟩ state,
// 1 if they were in |01⟩ state,
// 2 if they were in |10⟩ state,
// 3 if they were in |11⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation BasisStateMeasurement_Reference (qs : Qubit[]) : Int
{
body
{
// measurement on the first qubit gives the higher bit of the answer, on the second - the lower
mutable m1 = 0;
if (M(qs[0]) == One) {
set m1 = 1;
}
mutable m2 = 0;
if (M(qs[1]) == One) {
set m2 = 1;
}
return m1 * 2 + m2;
operation BasisStateMeasurement_Reference (qs : Qubit[]) : Int {
// measurement on the first qubit gives the higher bit of the answer, on the second - the lower
mutable m1 = 0;
if (M(qs[0]) == One) {
set m1 = 1;
}
mutable m2 = 0;
if (M(qs[1]) == One) {
set m2 = 1;
}
return m1 * 2 + m2;
}
// Task 1.7. Distinguish two basis states given by bit strings
// Inputs:
// 1) N qubits (stored in an array) which are guaranteed to be
// 1) N qubits (stored in an array) which are guaranteed to be
// in one of the two basis states described by the given bit strings.
// 2) two bit string represented as Bool[]s.
// Output: 0 if qubits were in the basis state described by the first bit string,
@ -136,95 +120,92 @@ namespace Quantum.Kata.Measurements
// You are guaranteed that the both bit strings have the same length as the qubit array,
// and that the bit strings will differ in at least one bit.
// You can use exactly one measurement.
// Example: for bit strings [false; true; false] and [false; false; true]
// Example: for bit strings [false, true, false] and [false, false, true]
// return 0 corresponds to state |010⟩, and return 1 corresponds to state |001⟩.
function FindFirstDiff_Reference (bits1 : Bool[], bits2 : Bool[]) : Int
{
function FindFirstDiff_Reference (bits1 : Bool[], bits2 : Bool[]) : Int {
mutable firstDiff = -1;
for (i in 0 .. Length(bits1)-1) {
for (i in 0 .. Length(bits1) - 1) {
if (bits1[i] != bits2[i] && firstDiff == -1) {
set firstDiff = i;
}
}
return firstDiff;
}
operation TwoBitstringsMeasurement_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Int
{
body
{
// find the first index at which the bit strings are different and measure it
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
let res = (M(qs[firstDiff]) == One);
if (res == bits1[firstDiff]) {
return 0;
} else {
return 1;
}
operation TwoBitstringsMeasurement_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Int {
// find the first index at which the bit strings are different and measure it
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
let res = M(qs[firstDiff]) == One;
if (res == bits1[firstDiff]) {
return 0;
} else {
return 1;
}
}
// Task 1.8. |0...0⟩ state or W state ?
// Input: N qubits (stored in an array) which are guaranteed to be
// Input: N qubits (stored in an array) which are guaranteed to be
// either in |0...0⟩ state
// or in W state (https://en.wikipedia.org/wiki/W_state).
// Output: 0 if qubits were in |0...0⟩ state,
// 1 if they were in W state.
// The state of the qubits at the end of the operation does not matter.
operation AllZerosOrWState_Reference (qs : Qubit[]) : Int
{
body
{
// measure all qubits; if there is exactly one One, it's W state, if there are no Ones, it's |0...0⟩
// (and there should never be two or more Ones)
mutable countOnes = 0;
for (i in 0..Length(qs)-1) {
if (M(qs[i]) == One) {
set countOnes = countOnes + 1;
}
operation AllZerosOrWState_Reference (qs : Qubit[]) : Int {
// measure all qubits; if there is exactly one One, it's W state, if there are no Ones, it's |0...0⟩
// (and there should never be two or more Ones)
mutable countOnes = 0;
for (i in 0 .. Length(qs) - 1) {
if (M(qs[i]) == One) {
set countOnes = countOnes + 1;
}
if (countOnes > 1) {
fail "Impossible to get multiple Ones when measuring W state";
}
if (countOnes == 0) {
return 0;
}
return 1;
}
if (countOnes > 1) {
fail "Impossible to get multiple Ones when measuring W state";
}
if (countOnes == 0) {
return 0;
}
return 1;
}
// Task 1.9. GHZ state or W state ?
// Input: N >= 2 qubits (stored in an array) which are guaranteed to be
// Input: N >= 2 qubits (stored in an array) which are guaranteed to be
// either in GHZ state (https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state)
// or in W state (https://en.wikipedia.org/wiki/W_state).
// Output: 0 if qubits were in GHZ state,
// 1 if they were in W state.
// The state of the qubits at the end of the operation does not matter.
operation GHZOrWState_Reference (qs : Qubit[]) : Int
{
body
{
// measure all qubits; if there is exactly one One, it's W state,
// if there are no Ones or all are Ones, it's GHZ
// (and there should never be a different number of Ones)
let N = Length(qs);
mutable countOnes = 0;
for (i in 0..N-1) {
if (M(qs[i]) == One) {
set countOnes = countOnes + 1;
}
operation GHZOrWState_Reference (qs : Qubit[]) : Int {
// measure all qubits; if there is exactly one One, it's W state,
// if there are no Ones or all are Ones, it's GHZ
// (and there should never be a different number of Ones)
let N = Length(qs);
mutable countOnes = 0;
for (i in 0 .. N - 1) {
if (M(qs[i]) == One) {
set countOnes = countOnes + 1;
}
if (countOnes > 1 && countOnes < Length(qs)) {
fail $"Impossible to get {countOnes} Ones when measuring W state or GHZ state on {N} qubits";
}
if (countOnes == 1) {
return 1;
}
return 0;
}
if (countOnes > 1 && countOnes < Length(qs)) {
fail $"Impossible to get {countOnes} Ones when measuring W state or GHZ state on {N} qubits";
}
if (countOnes == 1) {
return 1;
}
return 0;
}
// Task 1.10. Distinguish four Bell states
// Input: two qubits (stored in an array) which are guaranteed to be in one of the four Bell states:
// |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
@ -236,26 +217,26 @@ namespace Quantum.Kata.Measurements
// 2 if they were in |Ψ⁺⟩ state,
// 3 if they were in |Ψ⁻⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation BellState_Reference (qs : Qubit[]) : Int
{
body
{
H(qs[0]);
H(qs[1]);
CNOT(qs[1], qs[0]);
H(qs[1]);
mutable m1 = 0;
if (M(qs[0]) == One) {
set m1 = 1;
}
mutable m2 = 0;
if (M(qs[1]) == One) {
set m2 = 1;
}
return m2 * 2 + m1;
}
}
operation BellState_Reference (qs : Qubit[]) : Int {
H(qs[0]);
H(qs[1]);
CNOT(qs[1], qs[0]);
H(qs[1]);
mutable m1 = 0;
if (M(qs[0]) == One) {
set m1 = 1;
}
mutable m2 = 0;
if (M(qs[1]) == One) {
set m2 = 1;
}
return m2 * 2 + m1;
}
// Task 1.11*. Distinguish four orthogonal 2-qubit states
// Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states:
// |S0⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2
@ -267,19 +248,16 @@ namespace Quantum.Kata.Measurements
// 2 if they were in |S2⟩ state,
// 3 if they were in |S3⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation TwoQubitState_Reference (qs : Qubit[]) : Int
{
body
{
// These states are produced by H ⊗ H, applied to four basis states.
// To measure them, apply H ⊗ H followed by basis state measurement
// implemented in BasisStateMeasurement_Reference.
H(qs[0]);
H(qs[1]);
return BasisStateMeasurement_Reference(qs);
}
operation TwoQubitState_Reference (qs : Qubit[]) : Int {
// These states are produced by H ⊗ H, applied to four basis states.
// To measure them, apply H ⊗ H followed by basis state measurement
// implemented in BasisStateMeasurement_Reference.
H(qs[0]);
H(qs[1]);
return BasisStateMeasurement_Reference(qs);
}
// Task 1.12**. Distinguish four orthogonal 2-qubit states, part two
// Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states:
// |S0⟩ = ( |00⟩ - |01⟩ - |10⟩ - |11⟩) / 2
@ -293,69 +271,69 @@ namespace Quantum.Kata.Measurements
// The state of the qubits at the end of the operation does not matter.
// Helper function to implement diag(-1, 1, 1, 1)
operation ApplyDiag (qs : Qubit[]) : ()
{
body
{
ApplyToEach(X, qs);
(Controlled Z)([qs[0]], qs[1]);
ApplyToEach(X, qs);
operation ApplyDiag (qs : Qubit[]) : Unit {
body (...) {
ApplyToEach(X, qs);
Controlled Z([qs[0]], qs[1]);
ApplyToEach(X, qs);
}
adjoint self
adjoint self;
}
// The actual reference implementation for Task 1.11
operation TwoQubitStatePartTwo_Reference (qs : Qubit[]) : Int
{
body
{
// Observe that the unitary matrix A formed by the columns |S0⟩, ..., |S3⟩
// is up to permutations matrices and diagonal +1/-1 matrices equal to the
// tensor product H ⊗ H when multiplied from the left and the right.
// Specifically, A = diag(-1, 1, 1, 1) (H ⊗ H) diag(-1, 1, 1, 1) pi,
// where pi is the permutation (1,2) corresponding to a swap of 2 qubits.
SWAP(qs[0], qs[1]); // pi
With(ApplyDiag, ApplyToEach(H, _), qs); // diag(..) (H ⊗ H) diag(..)
return BasisStateMeasurement_Reference(qs);
}
operation TwoQubitStatePartTwo_Reference (qs : Qubit[]) : Int {
// Observe that the unitary matrix A formed by the columns |S0⟩, ..., |S3⟩
// is up to permutations matrices and diagonal +1/-1 matrices equal to the
// tensor product H ⊗ H when multiplied from the left and the right.
// Specifically, A = diag(-1, 1, 1, 1) (H ⊗ H) diag(-1, 1, 1, 1) pi,
// where pi is the permutation (1,2) corresponding to a swap of 2 qubits.
// Apply permutation pi
SWAP(qs[0], qs[1]);
// Apply diag(..) (H ⊗ H) diag(..)
With(ApplyDiag, ApplyToEach(H, _), qs);
return BasisStateMeasurement_Reference(qs);
}
//////////////////////////////////////////////////////////////////
// Part II*. Discriminating Nonorthogonal States
//////////////////////////////////////////////////////////////////
// Task 2.1*. |0⟩ or |+⟩ ?
// (quantum hypothesis testing or state discrimination with minimum error)
// Input: a qubit which is guaranteed to be in |0⟩ or |+⟩ state with equal probability.
// Output: true if qubit was in |0⟩ state, or false if it was in |+⟩ state.
// The state of the qubit at the end of the operation does not matter.
// Note: in this task you have to get accuracy of at least 80%.
operation IsQubitPlusOrZero_Reference (q : Qubit) : Bool
{
body
{
// Let {E_a, E_b} be a measurement with two outcomes a and b, which we identify with
// the answers, i.e., "a" = "state was |0⟩" and "b = state was |+⟩". Then we define
// P(a|0) = probability to observe first outcome given that the state was |0⟩
// P(b|0) = probability to observe second outcome given that the state was |0⟩
// P(a|+) = probability to observe first outcome given that the state was |+⟩
// P(b|+) = probability to observe second outcome given that the state was |+⟩
// the task is to maximize the probability to be correct on a single shot experiment
// which is the same as to minimize the probability to be wrong (on a single shot).
// Assuming uniform prior, i.e., P(+) = P(0) = 1/2, we get
// P_correct = P(0) P(a|0) + P(+) P(b|+). Assuming a von Neumann measurement of the
// form E_a = Ry(2*alpha) * (1,0) = (cos(alpha), sin(alpha)) and
// E_b = Ry(2*alpha) * (0,1) = (sin(alpha), -cos(alpha)), we get that
// P_correct = 1/2 + cos²(alpha) + cos(alpha) sin(alpha). Maximizing this for alpha,
// we get max P_success = 1/2 (1 + 1/sqrt(2)) = 0.8535.., which is attained for alpha = π/8.
// Rotate the input state by π/8 means to apply Ry with angle 2π/8.
Ry(0.25*PI(), q);
return (M(q) == Zero);
}
operation IsQubitPlusOrZero_Reference (q : Qubit) : Bool {
// Let {E_a, E_b} be a measurement with two outcomes a and b, which we identify with
// the answers, i.e., "a" = "state was |0⟩" and "b = state was |+⟩". Then we define
// P(a|0) = probability to observe first outcome given that the state was |0⟩
// P(b|0) = probability to observe second outcome given that the state was |0⟩
// P(a|+) = probability to observe first outcome given that the state was |+⟩
// P(b|+) = probability to observe second outcome given that the state was |+⟩
// the task is to maximize the probability to be correct on a single shot experiment
// which is the same as to minimize the probability to be wrong (on a single shot).
// Assuming uniform prior, i.e., P(+) = P(0) = 1/2, we get
// P_correct = P(0) P(a|0) + P(+) P(b|+). Assuming a von Neumann measurement of the
// form E_a = Ry(2*alpha) * (1,0) = (cos(alpha), sin(alpha)) and
// E_b = Ry(2*alpha) * (0,1) = (sin(alpha), -cos(alpha)), we get that
// P_correct = 1/2 + cos²(alpha) + cos(alpha) sin(alpha). Maximizing this for alpha,
// we get max P_success = 1/2 (1 + 1/sqrt(2)) = 0.8535.., which is attained for alpha = π/8.
// Rotate the input state by π/8 means to apply Ry with angle 2π/8.
Ry(0.25 * PI(), q);
return M(q) == Zero;
}
// Task 2.2**. |0⟩, |+⟩ or inconclusive?
// (unambiguous state discrimination)
// Input: a qubit which is guaranteed to be in |0⟩ or |+⟩ state with equal probability.
@ -364,64 +342,63 @@ namespace Quantum.Kata.Measurements
// -1 if you can't decide, i.e., an "inconclusive" result.
// Your solution:
// - can never give 0 or 1 answer incorrectly (i.e., identify |0⟩ as 1 or |+⟩ as 0).
// - must give inconclusive (-1) answer at most 80% of the times.
// - must give inconclusive (-1) answer at most 80% of the times.
// - must correctly identify |0⟩ state as 0 at least 10% of the times.
// - must correctly identify |+⟩ state as 1 at least 10% of the times.
//
// The state of the qubit at the end of the operation does not matter.
// You are allowed to use ancilla qubit(s).
operation IsQubitPlusZeroOrInconclusiveSimpleUSD_Reference (q : Qubit) : Int
{
body
{
// A simple strategy that gives an inconclusive result with probability 0.75
// and never errs in case it yields a conclusive result can be obtained from
// randomizing the choice of measurement basis between the computational basis (std)
// and the Hadamard basis (had). Observe that when measured in the standard basis,
// the state |0⟩ will always lead to the outcome "0", whereas the state |+⟩
// will lead to outcomes "0" respectively "1" with probability 1/2. This means
// that upon measuring "1" we can with certainty conclude that the state was |+⟩.
// A similar argument applies to the scenario where we measure in the Hadamard
// basis, where |0⟩ can lead to both outcomes, whereas |+⟩ always leads to "0".
// Then upon measuring "1" we can with certainty conclude that the state was |0⟩.
//
// This leads to the following scenarios (shown are the conditional probabilities
// of the above scenarios and resulting answers).
// state | basis | output 0 | output 1 | output -1
// -----------------------------------------------
// |0⟩ | std | 0 | 0 | 1
// |+⟩ | std | 0 | 1/2 | 1/2
// |0⟩ | had | 1/2 | 0 | 1/2
// |+⟩ | had | 0 | 0 | 1
// You are allowed to use ancilla qubit(s).
operation IsQubitPlusZeroOrInconclusiveSimpleUSD_Reference (q : Qubit) : Int {
// A simple strategy that gives an inconclusive result with probability 0.75
// and never errs in case it yields a conclusive result can be obtained from
// randomizing the choice of measurement basis between the computational basis (std)
// and the Hadamard basis (had). Observe that when measured in the standard basis,
// the state |0⟩ will always lead to the outcome "0", whereas the state |+⟩
// will lead to outcomes "0" respectively "1" with probability 1/2. This means
// that upon measuring "1" we can with certainty conclude that the state was |+⟩.
// A similar argument applies to the scenario where we measure in the Hadamard
// basis, where |0⟩ can lead to both outcomes, whereas |+⟩ always leads to "0".
// Then upon measuring "1" we can with certainty conclude that the state was |0⟩.
//
// This leads to the following scenarios (shown are the conditional probabilities
// of the above scenarios and resulting answers).
// state | basis | output 0 | output 1 | output -1
// -----------------------------------------------
// |0⟩ | std | 0 | 0 | 1
// |+⟩ | std | 0 | 1/2 | 1/2
// |0⟩ | had | 1/2 | 0 | 1/2
// |+⟩ | had | 0 | 0 | 1
mutable output = 0;
let basis = RandomInt(2);
// randomize over std and had
if (basis == 0) {
mutable output = 0;
let basis = RandomInt(2);
// randomize over std and had
if (basis == 0) {
// use standard basis
let result = M(q);
if (result == One) {
// this can only arise if the state was |+⟩
set output = 1;
}
else {
set output = -1;
}
// use standard basis
let result = M(q);
if (result == One) {
// this can only arise if the state was |+⟩
set output = 1;
}
else {
// use Hadamard basis
H(q);
let result = M(q);
if (result == One) {
// this can only arise if the state was |0⟩
set output = 0;
}
else {
set output = -1;
}
else {
set output = -1;
}
return output;
}
else {
// use Hadamard basis
H(q);
let result = M(q);
if (result == One) {
// this can only arise if the state was |0⟩
set output = 0;
}
else {
set output = -1;
}
}
return output;
}
}

Просмотреть файл

@ -1,126 +1,109 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.Measurements
{
namespace Quantum.Kata.Measurements {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Measurements" quantum kata is a series of exercises designed
// "Measurements" quantum kata is a series of exercises designed
// to get you familiar with programming in Q#.
// It covers the following topics:
// - single-qubit measurements,
// - discriminating orthogonal and nonorthogonal states.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
//////////////////////////////////////////////////////////////////
// Part I. Single-Qubit Measurements
//////////////////////////////////////////////////////////////////
// Task 1.1. |0⟩ or |1⟩ ?
// Input: a qubit which is guaranteed to be in |0⟩ or |1⟩ state.
// Output: true if qubit was in |1⟩ state, or false if it was in |0⟩ state.
// The state of the qubit at the end of the operation does not matter.
operation IsQubitOne (q : Qubit) : Bool
{
body
{
// ...
return false;
}
operation IsQubitOne (q : Qubit) : Bool {
// ...
return false;
}
// Task 1.2. Set qubit to |0⟩ state
// Input: a qubit in an arbitrary state.
// Goal: change the state of the qubit to |0⟩.
operation InitializeQubit (q : Qubit) : ()
{
body
{
// ...
}
operation InitializeQubit (q : Qubit) : Unit {
// ...
}
// Task 1.3. |+⟩ or |-⟩ ?
// Input: a qubit which is guaranteed to be in |+⟩ or |-⟩ state
// (|+⟩ = (|0⟩ + |1⟩) / sqrt(2), |-⟩ = (|0⟩ - |1⟩) / sqrt(2)).
// Output: true if qubit was in |+⟩ state, or false if it was in |-⟩ state.
// The state of the qubit at the end of the operation does not matter.
operation IsQubitPlus (q : Qubit) : Bool
{
body
{
// ...
return false;
}
operation IsQubitPlus (q : Qubit) : Bool {
// ...
return false;
}
// Task 1.4. |A⟩ or |B⟩ ?
// Inputs:
// 1) angle alpha, in radians, represented as Double
// 2) a qubit which is guaranteed to be in |A⟩ or |B⟩ state
// |A⟩ = cos(alpha) * |0⟩ + sin(alpha) * |1⟩,
// |A⟩ = cos(alpha) * |0⟩ + sin(alpha) * |1⟩,
// |B⟩ = - sin(alpha) * |0⟩ + cos(alpha) * |1⟩.
// Output: true if qubit was in |A⟩ state, or false if it was in |B⟩ state.
// The state of the qubit at the end of the operation does not matter.
operation IsQubitA (alpha : Double, q : Qubit) : Bool
{
body
{
// ...
return false;
}
operation IsQubitA (alpha : Double, q : Qubit) : Bool {
// ...
return false;
}
// Task 1.5. |00⟩ or |11⟩ ?
// Input: two qubits (stored in an array) which are guaranteed to be in |00⟩ or |11⟩ state.
// Output: 0 if qubits were in |00⟩ state,
// 1 if they were in |11⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation ZeroZeroOrOneOne (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation ZeroZeroOrOneOne (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 1.6. Distinguish four basis states
// Input: two qubits (stored in an array) which are guaranteed to be
// Input: two qubits (stored in an array) which are guaranteed to be
// in one of the four basis states (|00⟩, |01⟩, |10⟩ or |11⟩).
// Output: 0 if qubits were in |00⟩ state,
// 1 if they were in |01⟩ state,
// 2 if they were in |10⟩ state,
// 3 if they were in |11⟩ state.
// In this task and the subsequent ones the order of qubit states
// In this task and the subsequent ones the order of qubit states
// in task description matches the order of qubits in the array
// (i.e., |10⟩ state corresponds to qs[0] in state |1⟩ and qs[1] in state |0⟩).
// The state of the qubits at the end of the operation does not matter.
operation BasisStateMeasurement (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation BasisStateMeasurement (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 1.7. Distinguish two basis states given by bit strings
// Inputs:
// 1) N qubits (stored in an array) which are guaranteed to be
// 1) N qubits (stored in an array) which are guaranteed to be
// in one of the two basis states described by the given bit strings.
// 2) two bit string represented as Bool[]s.
// Output: 0 if qubits were in the basis state described by the first bit string,
@ -130,49 +113,40 @@ namespace Quantum.Kata.Measurements
// You are guaranteed that the both bit strings have the same length as the qubit array,
// and that the bit strings will differ in at least one bit.
// You can use exactly one measurement.
// Example: for bit strings [false; true; false] and [false; false; true]
// Example: for bit strings [false, true, false] and [false, false, true]
// return 0 corresponds to state |010⟩, and return 1 corresponds to state |001⟩.
operation TwoBitstringsMeasurement (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Int
{
body
{
// ...
return -1;
}
operation TwoBitstringsMeasurement (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Int {
// ...
return -1;
}
// Task 1.8. |0...0⟩ state or W state ?
// Input: N qubits (stored in an array) which are guaranteed to be
// Input: N qubits (stored in an array) which are guaranteed to be
// either in |0...0⟩ state
// or in W state (https://en.wikipedia.org/wiki/W_state).
// Output: 0 if qubits were in |0...0⟩ state,
// 1 if they were in W state.
// The state of the qubits at the end of the operation does not matter.
operation AllZerosOrWState (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation AllZerosOrWState (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 1.9. GHZ state or W state ?
// Input: N >= 2 qubits (stored in an array) which are guaranteed to be
// Input: N >= 2 qubits (stored in an array) which are guaranteed to be
// either in GHZ state (https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state)
// or in W state (https://en.wikipedia.org/wiki/W_state).
// Output: 0 if qubits were in GHZ state,
// 1 if they were in W state.
// The state of the qubits at the end of the operation does not matter.
operation GHZOrWState (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation GHZOrWState (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 1.10. Distinguish four Bell states
// Input: two qubits (stored in an array) which are guaranteed to be in one of the four Bell states:
// |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
@ -184,17 +158,14 @@ namespace Quantum.Kata.Measurements
// 2 if they were in |Ψ⁺⟩ state,
// 3 if they were in |Ψ⁻⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation BellState (qs : Qubit[]) : Int
{
body
{
// Hint: you need to use 2-qubit gates to solve this task
// ...
return -1;
}
operation BellState (qs : Qubit[]) : Int {
// Hint: you need to use 2-qubit gates to solve this task
// ...
return -1;
}
// Task 1.11*. Distinguish four orthogonal 2-qubit states
// Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states:
// |S0⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2
@ -206,15 +177,12 @@ namespace Quantum.Kata.Measurements
// 2 if they were in |S2⟩ state,
// 3 if they were in |S3⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation TwoQubitState (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation TwoQubitState (qs : Qubit[]) : Int {
// ...
return -1;
}
// Task 1.12**. Distinguish four orthogonal 2-qubit states, part two
// Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states:
// |S0⟩ = ( |00⟩ - |01⟩ - |10⟩ - |11⟩) / 2
@ -226,41 +194,34 @@ namespace Quantum.Kata.Measurements
// 2 if they were in |S2⟩ state,
// 3 if they were in |S3⟩ state.
// The state of the qubits at the end of the operation does not matter.
operation TwoQubitStatePartTwo (qs : Qubit[]) : Int
{
body
{
// ...
return -1;
}
operation TwoQubitStatePartTwo (qs : Qubit[]) : Int {
// ...
return -1;
}
//////////////////////////////////////////////////////////////////
// Part II*. Discriminating Nonorthogonal States
//////////////////////////////////////////////////////////////////
// The solutions for tasks in this section are validated using the following method.
// The solution is called on N input states, each of which is picked randomly,
// The solution is called on N input states, each of which is picked randomly,
// with all possible input states equally likely to be generated.
// The accuracy of state discrimination is estimated as an average of
// The accuracy of state discrimination is estimated as an average of
// discrimination correctness over all input states.
// Task 2.1*. |0⟩ or |+⟩ ?
// (quantum hypothesis testing or state discrimination with minimum error)
// Input: a qubit which is guaranteed to be in |0⟩ or |+⟩ state with equal probability.
// Output: true if qubit was in |0⟩ state, or false if it was in |+⟩ state.
// The state of the qubit at the end of the operation does not matter.
// Note: in this task you have to get accuracy of at least 80%.
operation IsQubitPlusOrZero (q : Qubit) : Bool
{
body
{
// ...
return true;
}
operation IsQubitPlusOrZero (q : Qubit) : Bool {
// ...
return true;
}
// Task 2.2**. |0⟩, |+⟩ or inconclusive?
// (unambiguous state discrimination)
// Input: a qubit which is guaranteed to be in |0⟩ or |+⟩ state with equal probability.
@ -269,18 +230,15 @@ namespace Quantum.Kata.Measurements
// -1 if you can't decide, i.e., an "inconclusive" result.
// Your solution:
// - can never give 0 or 1 answer incorrectly (i.e., identify |0⟩ as 1 or |+⟩ as 0).
// - must give inconclusive (-1) answer at most 80% of the times.
// - must give inconclusive (-1) answer at most 80% of the times.
// - must correctly identify |0⟩ state as 0 at least 10% of the times.
// - must correctly identify |+⟩ state as 1 at least 10% of the times.
//
// The state of the qubit at the end of the operation does not matter.
// You are allowed to use ancilla qubit(s).
operation IsQubitPlusZeroOrInconclusiveSimpleUSD (q : Qubit) : Int
{
body
{
// ...
return -2;
}
// You are allowed to use ancilla qubit(s).
operation IsQubitPlusZeroOrInconclusiveSimpleUSD (q : Qubit) : Int {
// ...
return -2;
}
}

Просмотреть файл

@ -1,284 +1,254 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.Measurements
{
namespace Quantum.Kata.Measurements {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Testing;
//////////////////////////////////////////////////////////////////
// "Framework" operation for testing single-qubit tasks for distinguishing states of one qubit
// with Bool return
operation DistinguishTwoStates_OneQubit (
statePrep : ((Qubit, Int) => ()),
testImpl : (Qubit => Bool)
) : ()
{
body
{
let nTotal = 100;
mutable nOk = 0;
using (qs = Qubit[1])
{
for (i in 1..nTotal)
{
// get a random bit to define whether qubit will be in a state corresponding to true return (1) or to false one (0)
// state = 0 false return
// state = 1 true return
let state = RandomIntPow2(1);
// do state prep: convert |0⟩ to outcome with false return or to outcome with true return depending on state
statePrep(qs[0], state);
operation DistinguishTwoStates_OneQubit (statePrep : ((Qubit, Int) => Unit), testImpl : (Qubit => Bool)) : Unit {
let nTotal = 100;
mutable nOk = 0;
// get the solution's answer and verify that it's a match
let ans = testImpl(qs[0]);
if (ans == (state == 1)) {
set nOk = nOk + 1;
}
// we're not checking the state of the qubit after the operation
Reset(qs[0]);
using (qs = Qubit[1]) {
for (i in 1 .. nTotal) {
// get a random bit to define whether qubit will be in a state corresponding to true return (1) or to false one (0)
// state = 0 false return
// state = 1 true return
let state = RandomIntPow2(1);
// do state prep: convert |0⟩ to outcome with false return or to outcome with true return depending on state
statePrep(qs[0], state);
// get the solution's answer and verify that it's a match
let ans = testImpl(qs[0]);
if (ans == (state == 1)) {
set nOk = nOk + 1;
}
// we're not checking the state of the qubit after the operation
Reset(qs[0]);
}
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
}
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
}
// ------------------------------------------------------
operation StatePrep_IsQubitOne (q : Qubit, state : Int) : Unit {
if (state == 0) {
// convert |0⟩ to |0⟩
} else {
// convert |0⟩ to |1⟩
X(q);
}
}
operation T101_IsQubitOne_Test () : Unit {
DistinguishTwoStates_OneQubit(StatePrep_IsQubitOne, IsQubitOne);
}
// ------------------------------------------------------
operation StatePrep_IsQubitOne (q : Qubit, state : Int) : () {
body {
if (state == 0) {
// convert |0⟩ to |0⟩
} else {
// convert |0⟩ to |1⟩
X(q);
operation T102_InitializeQubit_Test () : Unit {
using (qs = Qubit[1]) {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
Ry(2.0 * alpha, qs[0]);
// Test Task 1
InitializeQubit(qs[0]);
// Confirm that the state is |0⟩.
AssertAllZero(qs);
}
}
}
operation T101_IsQubitOne_Test () : ()
{
body
{
DistinguishTwoStates_OneQubit(StatePrep_IsQubitOne, IsQubitOne);
}
}
// ------------------------------------------------------
operation T102_InitializeQubit_Test () : ()
{
body
{
using (qs = Qubit[1])
{
for (i in 0..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
Ry(2.0 * alpha, qs[0]);
// Test Task 1
InitializeQubit(qs[0]);
// Confirm that the state is |0⟩.
AssertAllZero(qs);
}
}
operation StatePrep_IsQubitPlus (q : Qubit, state : Int) : Unit {
if (state == 0) {
// convert |0⟩ to |-⟩
X(q);
H(q);
} else {
// convert |0⟩ to |+⟩
H(q);
}
}
operation T103_IsQubitPlus_Test () : Unit {
DistinguishTwoStates_OneQubit(StatePrep_IsQubitPlus, IsQubitPlus);
}
// ------------------------------------------------------
operation StatePrep_IsQubitPlus (q : Qubit, state : Int) : () {
body {
if (state == 0) {
// convert |0⟩ to |-⟩
X(q);
H(q);
} else {
// convert |0⟩ to |+⟩
H(q);
}
}
}
operation T103_IsQubitPlus_Test () : ()
{
body
{
DistinguishTwoStates_OneQubit(StatePrep_IsQubitPlus, IsQubitPlus);
}
}
// ------------------------------------------------------
// |A⟩ = cos(alpha) * |0⟩ + sin(alpha) * |1⟩,
// |A⟩ = cos(alpha) * |0⟩ + sin(alpha) * |1⟩,
// |B⟩ = - sin(alpha) * |0⟩ + cos(alpha) * |1⟩.
operation StatePrep_IsQubitA (alpha : Double, q : Qubit, state : Int) : () {
body {
if (state == 0) {
// convert |0⟩ to |B⟩
X(q);
Ry(2.0 * alpha, q);
} else {
// convert |0⟩ to |A⟩
Ry(2.0 * alpha, q);
}
operation StatePrep_IsQubitA (alpha : Double, q : Qubit, state : Int) : Unit {
if (state == 0) {
// convert |0⟩ to |B⟩
X(q);
Ry(2.0 * alpha, q);
} else {
// convert |0⟩ to |A⟩
Ry(2.0 * alpha, q);
}
}
operation T104_IsQubitA_Test () : ()
{
body
{
// cross-test
// alpha = 0.0 or PI() => !isQubitOne
// alpha = PI() / 2.0 => isQubitOne
DistinguishTwoStates_OneQubit(StatePrep_IsQubitOne, IsQubitA(PI() / 2.0, _));
// alpha = PI() / 4.0 => isQubitPlus
DistinguishTwoStates_OneQubit(StatePrep_IsQubitPlus, IsQubitA(PI() / 4.0, _));
for (i in 0..10) {
let alpha = PI() * ToDouble(i) / 10.0;
DistinguishTwoStates_OneQubit(StatePrep_IsQubitA(alpha, _, _), IsQubitA(alpha, _));
}
operation T104_IsQubitA_Test () : Unit {
// cross-test
// alpha = 0.0 or PI() => !isQubitOne
// alpha = PI() / 2.0 => isQubitOne
DistinguishTwoStates_OneQubit(StatePrep_IsQubitOne, IsQubitA(PI() / 2.0, _));
// alpha = PI() / 4.0 => isQubitPlus
DistinguishTwoStates_OneQubit(StatePrep_IsQubitPlus, IsQubitA(PI() / 4.0, _));
for (i in 0 .. 10) {
let alpha = (PI() * ToDouble(i)) / 10.0;
DistinguishTwoStates_OneQubit(StatePrep_IsQubitA(alpha, _, _), IsQubitA(alpha, _));
}
}
// ------------------------------------------------------
// "Framework" operation for testing multi-qubit tasks for distinguishing states of an array of qubits
// with Int return
operation DistinguishStates_MultiQubit (
Nqubit : Int,
Nstate : Int,
statePrep : ((Qubit[], Int) => ()),
testImpl : (Qubit[] => Int)
) : ()
{
body
{
let nTotal = 100;
mutable nOk = 0;
using (qs = Qubit[Nqubit])
{
for (i in 1..nTotal)
{
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// do state prep: convert |0...0⟩ to outcome with return equal to state
statePrep(qs, state);
operation DistinguishStates_MultiQubit (Nqubit : Int, Nstate : Int, statePrep : ((Qubit[], Int) => Unit), testImpl : (Qubit[] => Int)) : Unit {
let nTotal = 100;
mutable nOk = 0;
// get the solution's answer and verify that it's a match
let ans = testImpl(qs);
if (ans == state) {
set nOk = nOk + 1;
}
// we're not checking the state of the qubit after the operation
ResetAll(qs);
using (qs = Qubit[Nqubit]) {
for (i in 1 .. nTotal) {
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// do state prep: convert |0...0⟩ to outcome with return equal to state
statePrep(qs, state);
// get the solution's answer and verify that it's a match
let ans = testImpl(qs);
if (ans == state) {
set nOk = nOk + 1;
}
// we're not checking the state of the qubit after the operation
ResetAll(qs);
}
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
}
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
}
// ------------------------------------------------------
operation StatePrep_ZeroZeroOrOneOne (qs : Qubit[], state : Int) : () {
body {
if (state == 1) {
// |11⟩
X(qs[0]);
X(qs[1]);
}
operation StatePrep_ZeroZeroOrOneOne (qs : Qubit[], state : Int) : Unit {
if (state == 1) {
// |11⟩
X(qs[0]);
X(qs[1]);
}
}
operation T105_ZeroZeroOrOneOne_Test () : () {
body {
DistinguishStates_MultiQubit(2, 2, StatePrep_ZeroZeroOrOneOne, ZeroZeroOrOneOne);
}
operation T105_ZeroZeroOrOneOne_Test () : Unit {
DistinguishStates_MultiQubit(2, 2, StatePrep_ZeroZeroOrOneOne, ZeroZeroOrOneOne);
}
// ------------------------------------------------------
operation StatePrep_BasisStateMeasurement (qs : Qubit[], state : Int) : () {
body {
if (state / 2 == 1) {
// |10⟩ or |11⟩
X(qs[0]);
}
if (state % 2 == 1) {
// |01⟩ or |11⟩
X(qs[1]);
}
operation StatePrep_BasisStateMeasurement (qs : Qubit[], state : Int) : Unit {
if (state / 2 == 1) {
// |10⟩ or |11⟩
X(qs[0]);
}
if (state % 2 == 1) {
// |01⟩ or |11⟩
X(qs[1]);
}
}
operation T106_BasisStateMeasurement_Test () : () {
body {
DistinguishStates_MultiQubit(2, 4, StatePrep_BasisStateMeasurement, BasisStateMeasurement);
}
operation T106_BasisStateMeasurement_Test () : Unit {
DistinguishStates_MultiQubit(2, 4, StatePrep_BasisStateMeasurement, BasisStateMeasurement);
}
// ------------------------------------------------------
operation StatePrep_Bitstring (qs : Qubit[], bits : Bool[]) : () {
body {
for (i in 0..Length(qs)-1) {
if (bits[i]) {
X(qs[i]);
}
operation StatePrep_Bitstring (qs : Qubit[], bits : Bool[]) : Unit {
for (i in 0 .. Length(qs) - 1) {
if (bits[i]) {
X(qs[i]);
}
}
}
operation StatePrep_TwoBitstringsMeasurement (qs : Qubit[], bits1 : Bool[], bits2 : Bool[], state : Int) : () {
body {
if (state == 0) {
StatePrep_Bitstring(qs, bits1);
} else {
StatePrep_Bitstring(qs, bits2);
}
operation StatePrep_TwoBitstringsMeasurement (qs : Qubit[], bits1 : Bool[], bits2 : Bool[], state : Int) : Unit {
if (state == 0) {
StatePrep_Bitstring(qs, bits1);
} else {
StatePrep_Bitstring(qs, bits2);
}
}
operation T107_TwoBitstringsMeasurement_Test () : () {
body {
for (i in 1..1) {
let b1 = [false; true];
let b2 = [true; false];
DistinguishStates_MultiQubit(2, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
for (i in 1..1) {
let b1 = [true; true; false];
let b2 = [false; true; true];
DistinguishStates_MultiQubit(3, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
for (i in 1..1) {
let b1 = [false; true; true; false];
let b2 = [false; true; true; true];
DistinguishStates_MultiQubit(4, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
for (i in 1..1) {
let b1 = [true; false; false; false];
let b2 = [true; false; true; true];
DistinguishStates_MultiQubit(4, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
operation T107_TwoBitstringsMeasurement_Test () : Unit {
for (i in 1 .. 1) {
let b1 = [false, true];
let b2 = [true, false];
DistinguishStates_MultiQubit(2, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
for (i in 1 .. 1) {
let b1 = [true, true, false];
let b2 = [false, true, true];
DistinguishStates_MultiQubit(3, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
for (i in 1 .. 1) {
let b1 = [false, true, true, false];
let b2 = [false, true, true, true];
DistinguishStates_MultiQubit(4, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
for (i in 1 .. 1) {
let b1 = [true, false, false, false];
let b2 = [true, false, true, true];
DistinguishStates_MultiQubit(4, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2));
}
}
// ------------------------------------------------------
operation WState_Arbitrary_Reference (qs : Qubit[]) : ()
{
body
{
operation WState_Arbitrary_Reference (qs : Qubit[]) : Unit {
body (...) {
let N = Length(qs);
if (N == 1) {
// base case of recursion: |1⟩
X(qs[0]);
@ -288,267 +258,260 @@ namespace Quantum.Kata.Measurements
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
let theta = ArcSin(1.0 / Sqrt(ToDouble(N)));
Ry(2.0 * theta, qs[0]);
// do a zero-controlled W-state generation for qubits 1..N-1
X(qs[0]);
(Controlled WState_Arbitrary_Reference)(qs[0..0], qs[1..N-1]);
Controlled WState_Arbitrary_Reference(qs[0 .. 0], qs[1 .. N - 1]);
X(qs[0]);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
operation StatePrep_AllZerosOrWState (qs : Qubit[], state : Int) : () {
body {
if (state == 1) {
// prep W state
WState_Arbitrary_Reference(qs);
}
operation StatePrep_AllZerosOrWState (qs : Qubit[], state : Int) : Unit {
if (state == 1) {
// prep W state
WState_Arbitrary_Reference(qs);
}
}
operation T108_AllZerosOrWState_Test () : () {
body {
for (i in 2..6) {
DistinguishStates_MultiQubit(i, 2, StatePrep_AllZerosOrWState, AllZerosOrWState);
}
operation T108_AllZerosOrWState_Test () : Unit {
for (i in 2 .. 6) {
DistinguishStates_MultiQubit(i, 2, StatePrep_AllZerosOrWState, AllZerosOrWState);
}
}
// ------------------------------------------------------
operation GHZ_State_Reference (qs : Qubit[]) : ()
{
body
{
operation GHZ_State_Reference (qs : Qubit[]) : Unit {
body (...) {
H(qs[0]);
for (i in 1 .. Length(qs)-1) {
for (i in 1 .. Length(qs) - 1) {
CNOT(qs[0], qs[i]);
}
}
adjoint auto;
adjoint invert;
}
operation StatePrep_GHZOrWState (qs : Qubit[], state : Int) : () {
body {
if (state == 0) {
// prep GHZ state
GHZ_State_Reference(qs);
} else {
// prep W state
WState_Arbitrary_Reference(qs);
}
operation StatePrep_GHZOrWState (qs : Qubit[], state : Int) : Unit {
if (state == 0) {
// prep GHZ state
GHZ_State_Reference(qs);
} else {
// prep W state
WState_Arbitrary_Reference(qs);
}
}
operation T109_GHZOrWState_Test () : () {
body {
for (i in 2..6) {
DistinguishStates_MultiQubit(i, 2, StatePrep_GHZOrWState, GHZOrWState);
}
operation T109_GHZOrWState_Test () : Unit {
for (i in 2 .. 6) {
DistinguishStates_MultiQubit(i, 2, StatePrep_GHZOrWState, GHZOrWState);
}
}
// ------------------------------------------------------
// 0 - |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
// 1 - |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
// 2 - |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
// 3 - |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
operation StatePrep_BellState (qs : Qubit[], state : Int) : () {
body {
H(qs[0]);
CNOT(qs[0], qs[1]);
// now we have |00⟩ + |11⟩ - modify it based on state arg
if (state % 2 == 1) {
// negative phase
Z(qs[1]);
}
if (state / 2 == 1) {
X(qs[1]);
}
operation StatePrep_BellState (qs : Qubit[], state : Int) : Unit {
H(qs[0]);
CNOT(qs[0], qs[1]);
// now we have |00⟩ + |11⟩ - modify it based on state arg
if (state % 2 == 1) {
// negative phase
Z(qs[1]);
}
if (state / 2 == 1) {
X(qs[1]);
}
}
operation T110_BellState_Test () : () {
body {
DistinguishStates_MultiQubit(2, 4, StatePrep_BellState, BellState);
}
operation T110_BellState_Test () : Unit {
DistinguishStates_MultiQubit(2, 4, StatePrep_BellState, BellState);
}
// ------------------------------------------------------
// 0 - (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2
// 1 - (|00⟩ - |01⟩ + |10⟩ - |11⟩) / 2
// 2 - (|00⟩ + |01⟩ - |10⟩ - |11⟩) / 2
// 3 - (|00⟩ - |01⟩ - |10⟩ + |11⟩) / 2
operation StatePrep_TwoQubitState (qs : Qubit[], state : Int) : () {
body {
// start with state prep of basis vectors
StatePrep_BasisStateMeasurement(qs, state);
H(qs[0]);
H(qs[1]);
}
operation StatePrep_TwoQubitState (qs : Qubit[], state : Int) : Unit {
// start with state prep of basis vectors
StatePrep_BasisStateMeasurement(qs, state);
H(qs[0]);
H(qs[1]);
}
// ------------------------------------------------------
// 0 - ( |00⟩ - |01⟩ - |10⟩ - |11⟩) / 2
// 1 - (-|00⟩ + |01⟩ - |10⟩ - |11⟩) / 2
// 2 - (-|00⟩ - |01⟩ + |10⟩ - |11⟩) / 2
// 3 - (-|00⟩ - |01⟩ - |10⟩ + |11⟩) / 2
operation StatePrep_TwoQubitStatePartTwo (qs : Qubit[], state : Int) : () {
body {
// start with state prep of basis vectors
StatePrep_BasisStateMeasurement(qs, state);
// now apply all gates for unitary in reference impl (in reverse + adjoint)
ApplyToEach(X, qs);
(Controlled Z)([qs[0]], qs[1]);
ApplyToEach(X, qs);
ApplyToEach(H, qs);
ApplyToEach(X, qs);
(Controlled Z)([qs[0]], qs[1]);
ApplyToEach(X, qs);
SWAP(qs[0], qs[1]);
}
operation StatePrep_TwoQubitStatePartTwo (qs : Qubit[], state : Int) : Unit {
// start with state prep of basis vectors
StatePrep_BasisStateMeasurement(qs, state);
// now apply all gates for unitary in reference impl (in reverse + adjoint)
ApplyToEach(X, qs);
Controlled Z([qs[0]], qs[1]);
ApplyToEach(X, qs);
ApplyToEach(H, qs);
ApplyToEach(X, qs);
Controlled Z([qs[0]], qs[1]);
ApplyToEach(X, qs);
SWAP(qs[0], qs[1]);
}
operation T111_TwoQubitState_Test () : () {
body {
DistinguishStates_MultiQubit(2, 4, StatePrep_TwoQubitState, TwoQubitState);
}
operation T111_TwoQubitState_Test () : Unit {
DistinguishStates_MultiQubit(2, 4, StatePrep_TwoQubitState, TwoQubitState);
}
operation T112_TwoQubitStatePartTwo_Test () : () {
body {
DistinguishStates_MultiQubit(2, 4, StatePrep_TwoQubitStatePartTwo, TwoQubitStatePartTwo);
}
operation T112_TwoQubitStatePartTwo_Test () : Unit {
DistinguishStates_MultiQubit(2, 4, StatePrep_TwoQubitStatePartTwo, TwoQubitStatePartTwo);
}
//////////////////////////////////////////////////////////////////
operation StatePrep_IsQubitZeroOrPlus (q : Qubit, state : Int) : () {
body {
if (state == 0) {
// convert |0⟩ to |0⟩
} else {
// convert |0⟩ to |+⟩
H(q);
}
operation StatePrep_IsQubitZeroOrPlus (q : Qubit, state : Int) : Unit {
if (state == 0) {
// convert |0⟩ to |0⟩
} else {
// convert |0⟩ to |+⟩
H(q);
}
}
// "Framework" operation for testing multi-qubit tasks for distinguishing states of an array of qubits
// with Int return. Framework tests against a threshold parameter for the fraction of runs that must succeed.
operation DistinguishStates_MultiQubit_Threshold (
Nqubit : Int,
Nstate : Int,
threshold : Double,
statePrep : ((Qubit, Int) => ()),
testImpl : (Qubit => Bool)
) : ()
{
body
{
let nTotal = 1000;
mutable nOk = 0;
using (qs = Qubit[Nqubit])
{
for (i in 1..nTotal)
{
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// do state prep: convert |0⟩ to outcome with return equal to state
statePrep(qs[0], state);
// get the solution's answer and verify that it's a match
let ans = testImpl(qs[0]);
if (ans == (state == 0)) {
set nOk = nOk + 1;
}
// we're not checking the state of the qubit after the operation
ResetAll(qs);
operation DistinguishStates_MultiQubit_Threshold (Nqubit : Int, Nstate : Int, threshold : Double, statePrep : ((Qubit, Int) => Unit), testImpl : (Qubit => Bool)) : Unit {
let nTotal = 1000;
mutable nOk = 0;
using (qs = Qubit[Nqubit]) {
for (i in 1 .. nTotal) {
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// do state prep: convert |0⟩ to outcome with return equal to state
statePrep(qs[0], state);
// get the solution's answer and verify that it's a match
let ans = testImpl(qs[0]);
if (ans == (state == 0)) {
set nOk = nOk + 1;
}
}
if (ToDouble(nOk) < threshold * ToDouble(nTotal)) {
fail $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state which does not meet the required threshold of at least {threshold*100}%.";
// we're not checking the state of the qubit after the operation
ResetAll(qs);
}
}
if (ToDouble(nOk) < threshold * ToDouble(nTotal)) {
fail $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state which does not meet the required threshold of at least {threshold * 100.0}%.";
}
}
// "Framework" operation for testing multi-qubit tasks for distinguishing states of an array of qubits
// with Int return. Framework tests against a threshold parameter for the fraction of runs that must succeed.
// Framework tests in the USD scenario, i.e., it is allowed to respond "inconclusive" (with some probability)
// up to given threshold, but it is never allowed to err if an actual conclusive response is given.
operation USD_DistinguishStates_MultiQubit_Threshold (
Nqubit : Int,
Nstate : Int,
thresholdInconcl : Double,
thresholdConcl : Double,
statePrep : ((Qubit, Int) => ()),
testImpl : (Qubit => Int)
) : ()
{
body
{
let nTotal = 10000;
mutable nInconc = 0; // counts total inconclusive answers
mutable nConclOne = 0; // counts total conclusive |0⟩ state identifications
mutable nConclPlus = 0; // counts total conclusive |+> state identifications
using (qs = Qubit[Nqubit])
{
for (i in 1..nTotal)
{
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// do state prep: convert |0⟩ to outcome with return equal to state
statePrep(qs[0], state);
// get the solution's answer and verify that it's a match
let ans = testImpl(qs[0]);
// check that the answer is actually in allowed range
if (ans < -1 || ans > 1) {
fail $"state {state} led to invalid response {ans}.";
}
// keep track of the number of inconclusive answers given
if (ans == -1) {
set nInconc = nInconc + 1;
}
if (ans == 0 && state == 0) {
set nConclOne = nConclOne + 1;
}
if (ans == 1 && state == 1) {
set nConclPlus = nConclPlus + 1;
}
// check if upon conclusive result the answer is actually correct
if ((ans == 0) && (state == 1) || (ans == 1) && (state == 0)) {
fail $"state {state} led to incorrect conclusive response {ans}.";
}
// we're not checking the state of the qubit after the operation
ResetAll(qs);
// up to given threshold, but it is never allowed to err if an actual conclusive response is given.
operation USD_DistinguishStates_MultiQubit_Threshold (Nqubit : Int, Nstate : Int, thresholdInconcl : Double, thresholdConcl : Double, statePrep : ((Qubit, Int) => Unit), testImpl : (Qubit => Int)) : Unit {
let nTotal = 10000;
// counts total inconclusive answers
mutable nInconc = 0;
// counts total conclusive |0⟩ state identifications
mutable nConclOne = 0;
// counts total conclusive |+> state identifications
mutable nConclPlus = 0;
using (qs = Qubit[Nqubit]) {
for (i in 1 .. nTotal) {
// get a random integer to define the state of the qubits
let state = RandomInt(Nstate);
// do state prep: convert |0⟩ to outcome with return equal to state
statePrep(qs[0], state);
// get the solution's answer and verify that it's a match
let ans = testImpl(qs[0]);
// check that the answer is actually in allowed range
if (ans < -1 || ans > 1) {
fail $"state {state} led to invalid response {ans}.";
}
}
if (ToDouble(nInconc) > thresholdInconcl * ToDouble(nTotal)) {
fail $"{nInconc} test runs out of {nTotal} returned inconclusive which does not meet the required threshold of at most {thresholdInconcl*100}%.";
}
if (ToDouble(nConclOne) < thresholdConcl * ToDouble(nTotal)) {
fail $"Only {nConclOne} test runs out of {nTotal} returned conclusive |0⟩ which does not meet the required threshold of at least {thresholdConcl*100}%.";
}
if (ToDouble(nConclPlus) < thresholdConcl * ToDouble(nTotal)) {
fail $"Only {nConclPlus} test runs out of {nTotal} returned conclusive |+> which does not meet the required threshold of at least {thresholdConcl*100}%.";
// keep track of the number of inconclusive answers given
if (ans == -1) {
set nInconc = nInconc + 1;
}
if (ans == 0 && state == 0) {
set nConclOne = nConclOne + 1;
}
if (ans == 1 && state == 1) {
set nConclPlus = nConclPlus + 1;
}
// check if upon conclusive result the answer is actually correct
if (ans == 0 && state == 1 || ans == 1 && state == 0) {
fail $"state {state} led to incorrect conclusive response {ans}.";
}
// we're not checking the state of the qubit after the operation
ResetAll(qs);
}
}
}
operation T201_IsQubitZeroOrPlus_Test () : () {
body {
DistinguishStates_MultiQubit_Threshold(1, 2, 0.8, StatePrep_IsQubitZeroOrPlus, IsQubitPlusOrZero);
if (ToDouble(nInconc) > thresholdInconcl * ToDouble(nTotal)) {
fail $"{nInconc} test runs out of {nTotal} returned inconclusive which does not meet the required threshold of at most {thresholdInconcl * 100.0}%.";
}
if (ToDouble(nConclOne) < thresholdConcl * ToDouble(nTotal)) {
fail $"Only {nConclOne} test runs out of {nTotal} returned conclusive |0⟩ which does not meet the required threshold of at least {thresholdConcl * 100.0}%.";
}
if (ToDouble(nConclPlus) < thresholdConcl * ToDouble(nTotal)) {
fail $"Only {nConclPlus} test runs out of {nTotal} returned conclusive |+> which does not meet the required threshold of at least {thresholdConcl * 100.0}%.";
}
}
operation T202_IsQubitZeroOrPlusSimpleUSD_Test () : () {
body {
USD_DistinguishStates_MultiQubit_Threshold(1, 2, 0.8, 0.1, StatePrep_IsQubitZeroOrPlus, IsQubitPlusZeroOrInconclusiveSimpleUSD);
}
operation T201_IsQubitZeroOrPlus_Test () : Unit {
DistinguishStates_MultiQubit_Threshold(1, 2, 0.8, StatePrep_IsQubitZeroOrPlus, IsQubitPlusOrZero);
}
}
operation T202_IsQubitZeroOrPlusSimpleUSD_Test () : Unit {
USD_DistinguishStates_MultiQubit_Threshold(1, 2, 0.8, 0.1, StatePrep_IsQubitZeroOrPlus, IsQubitPlusZeroOrInconclusiveSimpleUSD);
}
}

Просмотреть файл

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.QEC_BitFlipCode</RootNamespace>
@ -10,9 +10,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -2,86 +2,89 @@
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.QEC_BitFlipCode {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
// Task 1. Parity Measurements
operation MeasureParity_Reference (register : Qubit[]) : Result {
body {
return Measure([PauliZ; PauliZ; PauliZ], register);
}
return Measure([PauliZ, PauliZ, PauliZ], register);
}
// Task 2. Encoding Codewords
operation Encode_Reference(register : Qubit[]) : () {
body {
operation Encode_Reference (register : Qubit[]) : Unit {
body (...) {
ApplyToEachA(CNOT(Head(register), _), Rest(register));
}
adjoint auto;
adjoint invert;
}
// Task 3. Error Detection I
operation DetectErrorOnLeftQubit_Reference (register : Qubit[]) : Result {
body {
return Measure([PauliZ; PauliZ], register[0..1]);
}
return Measure([PauliZ, PauliZ], register[0 .. 1]);
}
// Task 4. Error Correction I
operation CorrectErrorOnLeftQubit_Reference (register : Qubit[]) : () {
body {
if (Measure([PauliZ; PauliZ], register[0..1]) == One) {
X(register[0]);
}
operation CorrectErrorOnLeftQubit_Reference (register : Qubit[]) : Unit {
if (Measure([PauliZ, PauliZ], register[0 .. 1]) == One) {
X(register[0]);
}
}
// Task 5. Error Detection II
operation DetectErrorOnAnyQubit_Reference (register : Qubit[]) : Int {
body {
let m1 = Measure([PauliZ; PauliZ], register[0..1]);
let m2 = Measure([PauliZ; PauliZ], register[1..2]);
if (m1 == One && m2 == Zero) {
return 1;
}
if (m1 == One && m2 == One) {
return 2;
}
if (m1 == Zero && m2 == One) {
return 3;
}
return 0;
let m1 = Measure([PauliZ, PauliZ], register[0 .. 1]);
let m2 = Measure([PauliZ, PauliZ], register[1 .. 2]);
if (m1 == One && m2 == Zero) {
return 1;
}
if (m1 == One && m2 == One) {
return 2;
}
if (m1 == Zero && m2 == One) {
return 3;
}
return 0;
}
// Task 6. Error Correction II
operation CorrectErrorOnAnyQubit_Reference (register : Qubit[]) : () {
body {
let idx = DetectErrorOnAnyQubit_Reference(register);
if (idx > 0) {
X(register[idx - 1]);
}
operation CorrectErrorOnAnyQubit_Reference (register : Qubit[]) : Unit {
let idx = DetectErrorOnAnyQubit_Reference(register);
if (idx > 0) {
X(register[idx - 1]);
}
}
// Task 7. Logical X Gate
operation LogicalX_Reference (register : Qubit[]) : () {
body {
ApplyToEach(X, register);
}
operation LogicalX_Reference (register : Qubit[]) : Unit {
ApplyToEach(X, register);
}
// Task 8. Logical Z Gate
operation LogicalZ_Reference (register : Qubit[]) : () {
body {
ApplyToEach(Z, register);
}
operation LogicalZ_Reference (register : Qubit[]) : Unit {
ApplyToEach(Z, register);
}
}

Просмотреть файл

@ -2,33 +2,35 @@
// Licensed under the MIT license.
namespace Quantum.Kata.QEC_BitFlipCode {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// The "Quantum error correction - bit-flip code" quantum kata is
// a series of exercises designed to get you familiar with
// The "Quantum error correction - bit-flip code" quantum kata is
// a series of exercises designed to get you familiar with
// quantum error correction (QEC) and programming in Q#.
// It introduces you to the simplest of QEC codes - the three-qubit bit-flip code,
// which encodes each logical qubit in three physical qubits
// which encodes each logical qubit in three physical qubits
// and protects against single bit-flip error (equivalent to applying an X gate).
// In practice quantum systems can have other types of errors,
// In practice quantum systems can have other types of errors,
// which will be considered in the following katas on quantum error correction.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// Task 1. Parity Measurements
//
// Input: three qubits (stored as an array of length 3) in an unknown basis state
// Input: three qubits (stored as an array of length 3) in an unknown basis state
// or in a superposition of basis states of the same parity.
// Output: the parity of this state using exactly one call to Measure
// encoded as a value of Result type: Zero for parity 0 and One for parity 1.
@ -37,24 +39,22 @@ namespace Quantum.Kata.QEC_BitFlipCode {
// Example:
// |000⟩, |101⟩ and |011⟩ all have parity 0, while |010⟩ and |111⟩ have parity 1.
operation MeasureParity (register : Qubit[]) : Result {
body {
// Fill in your code here and change the return statement.
// ...
return Zero;
}
// Fill in your code here and change the return statement.
// ...
return Zero;
}
// Task 2. Encoding Codewords
//
// Input: three qubits in the state |ψ⟩ ⊗ |00⟩, where |ψ⟩ = α |0⟩ + β |1⟩ is
// the state of the first qubit, i.e., register[0].
// Goal: create a state |̅ψ⟩ ≔ α |000⟩ + β |111⟩ on these qubits.
operation Encode (register : Qubit[]) : () {
body {
// ...
}
operation Encode (register : Qubit[]) : Unit {
// ...
}
// Task 3. Error Detection I
//
// Input: three qubits that are either in the state |̅ψ⟩ ≔ α |000⟩ + β |111⟩
@ -65,25 +65,23 @@ namespace Quantum.Kata.QEC_BitFlipCode {
// One if the input is X𝟙𝟙|̅ψ⟩ (state with the error).
// After applying the operation the state of the qubits should not change.
operation DetectErrorOnLeftQubit (register : Qubit[]) : Result {
body {
// ...
return Zero;
}
// ...
return Zero;
}
// Task 4. Error Correction I
//
// Input: three qubits that are either in the state |̅ψ⟩ ≔ α |000⟩ + β |111⟩
// or in the state X𝟙𝟙|̅ψ⟩ = α |100⟩ + β |011⟩.
// Goal: make sure that the qubits are returned to the state |̅ψ⟩
// (i.e., determine whether an X error has occurred, and if so, fix it).
operation CorrectErrorOnLeftQubit (register : Qubit[]) : () {
body {
// Hint: you can use task 3 to figure out which state you are given.
// ...
}
operation CorrectErrorOnLeftQubit (register : Qubit[]) : Unit {
// Hint: you can use task 3 to figure out which state you are given.
// ...
}
// Task 5. Error Detection II
//
// Input: three qubits that are either in the state |̅ψ⟩ ≔ α |000⟩ + β |111⟩
@ -98,12 +96,11 @@ namespace Quantum.Kata.QEC_BitFlipCode {
// 𝟙𝟙X | 3
// After applying the operation the state of the qubits should not change.
operation DetectErrorOnAnyQubit (register : Qubit[]) : Int {
body {
// ...
return -1;
}
// ...
return -1;
}
// Task 6. Error Correction II
//
// Input: three qubits that are either in the state |̅ψ⟩ ≔ α |000⟩ + β |111⟩
@ -111,22 +108,21 @@ namespace Quantum.Kata.QEC_BitFlipCode {
// (i.e., the qubits start in state |̅ψ⟩ with an X error possibly applied to one of the qubits).
// Goal: make sure that the qubits are returned to the state |̅ψ⟩
// (i.e., determine whether an X error has occurred on any qubit, and if so, fix it).
operation CorrectErrorOnAnyQubit (register : Qubit[]) : () {
body {
// ...
}
operation CorrectErrorOnAnyQubit (register : Qubit[]) : Unit {
// ...
}
//////////////////////////////////////////////////////////////////
// All the tasks in this kata have been dealing with X errors on single qubit.
// The bit-flip code doesn't allow one to detect or correct a Z error or multiple X errors.
// Indeed, a Z error on a logical state |ψ⟩ = α |0⟩ + β |1⟩ encoded using the bit-flip code
// Indeed, a Z error on a logical state |ψ⟩ = α |0⟩ + β |1⟩ encoded using the bit-flip code
// would convert the state |̅ψ⟩ ≔ α |000⟩ + β |111⟩ into α |000⟩ - β |111⟩,
// which is a correct code word for logical state α |0⟩ - β |1⟩.
// Two X errors (say, on qubits 1 and 2) would convert |̅ψ⟩ to α |110⟩ + β |001⟩,
// which is a code word for logical state β |0⟩ + α |1⟩ with one X error on qubit 3.
//////////////////////////////////////////////////////////////////
// Task 7. Logical X Gate
//
// Input: three qubits that are either in the state |̅ψ⟩ ≔ α |000⟩ + β |111⟩
@ -136,12 +132,11 @@ namespace Quantum.Kata.QEC_BitFlipCode {
// ̅X |̅ψ⟩ = β |000⟩ + α |111⟩ or one of the states that can be represented as
// ̅X |̅ψ⟩ with an X error applied to one of the qubits (for example, β |010⟩ + α |101⟩).
// If the state has an error, you can fix it, but this is not necessary.
operation LogicalX (register : Qubit[]) : () {
body {
// ...
}
operation LogicalX (register : Qubit[]) : Unit {
// ...
}
// Task 8. Logical Z Gate
//
// Input: three qubits that are either in the state |̅ψ⟩ ≔ α |000⟩ + β |111⟩
@ -151,9 +146,8 @@ namespace Quantum.Kata.QEC_BitFlipCode {
// ̅Z |̅ψ⟩ = α |000⟩ - β |111⟩ or one of the states that can be represented as
// ̅Z |̅ψ⟩ with an X error applied to one of the qubits (for example, α |010⟩ - β |101⟩).
// If the state has an error, you can fix it, but this is not necessary.
operation LogicalZ (register : Qubit[]) : () {
body {
// ...
}
operation LogicalZ (register : Qubit[]) : Unit {
// ...
}
}

Просмотреть файл

@ -1,20 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains parts of the testing harness.
// 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.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.QEC_BitFlipCode {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Extensions.Bitwise;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Testing;
//////////////////////////////////////////////////////////////////////////
// Task 01
//////////////////////////////////////////////////////////////////////////
@ -25,43 +27,51 @@ namespace Quantum.Kata.QEC_BitFlipCode {
let b3 = bits % 2;
return $"{b1}{b2}{b3}";
}
operation StatePrep_Bitmask (qs : Qubit[], bits : Int) : () {
body {
operation StatePrep_Bitmask (qs : Qubit[], bits : Int) : Unit {
body (...) {
if (bits / 4 == 1) {
X(qs[0]);
}
if ((bits / 2) % 2 == 1) {
X(qs[1]);
}
if (bits % 2 == 1) {
X(qs[2]);
}
}
adjoint auto;
adjoint invert;
}
function FindFirstDiff_Reference (bits1 : Int[], bits2 : Int[]) : Int {
mutable firstDiff = -1;
for (i in 0 .. Length(bits1)-1) {
for (i in 0 .. Length(bits1) - 1) {
if (bits1[i] != bits2[i] && firstDiff == -1) {
set firstDiff = i;
}
}
return firstDiff;
}
function IntToBoolArray (n : Int) : Int[] {
return [(n / 4) % 2; (n / 2) % 2; n % 2];
return [(n / 4) % 2, (n / 2) % 2, n % 2];
}
operation StatePrep_TwoBitmasks (qs : Qubit[], bits1 : Int[], bits2 : Int[]) : () {
body {
operation StatePrep_TwoBitmasks (qs : Qubit[], bits1 : Int[], bits2 : Int[]) : Unit {
body (...) {
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
H(qs[firstDiff]);
for (i in 0 .. Length(qs)-1) {
for (i in 0 .. Length(qs) - 1) {
if (bits1[i] == bits2[i]) {
if (bits1[i] == 1) {
X(qs[i]);
@ -76,280 +86,270 @@ namespace Quantum.Kata.QEC_BitFlipCode {
}
}
}
adjoint auto;
adjoint invert;
}
operation TestParityOnState (
statePrep : (Qubit[] => () : Adjoint),
parity : Int,
stateStr : String
) : () {
body {
using (register = Qubit[3]) {
// prepare basis state to test on
statePrep(register);
let res = MeasureParity(register);
// check that the returned parity is correct
AssertBoolEqual(res == Zero, parity == 0, $"Failed on {stateStr}.");
// check that the state has not been modified
(Adjoint statePrep)(register);
AssertAllZero(register);
}
operation TestParityOnState (statePrep : (Qubit[] => Unit : Adjoint), parity : Int, stateStr : String) : Unit {
using (register = Qubit[3]) {
// prepare basis state to test on
statePrep(register);
let res = MeasureParity(register);
// check that the returned parity is correct
AssertBoolEqual(res == Zero, parity == 0, $"Failed on {stateStr}.");
// check that the state has not been modified
Adjoint statePrep(register);
AssertAllZero(register);
}
}
operation T01_MeasureParity_Test () : () {
body {
// test on all basis states
for (bits in 0..7) {
let bitsStr = ToString_Bitmask(bits);
TestParityOnState(StatePrep_Bitmask(_, bits), Parity(bits), $"basis state |{bitsStr}⟩");
}
// test on all superpositions of two basis states of the same parity
for (b1 in 0..7) {
let bits1 = IntToBoolArray(b1);
let bitsStr1 = ToString_Bitmask(b1);
for (b2 in (b1 + 1)..7) {
if (Parity(b1) == Parity(b2)) {
let bits2 = IntToBoolArray(b2);
let bitsStr2 = ToString_Bitmask(b2);
let p = Parity(b1);
Message($"Testing on |{bitsStr1}⟩ + |{bitsStr2}⟩ with parity {p}");
TestParityOnState(StatePrep_TwoBitmasks(_, bits1, bits2), Parity(b1),
$"state |{bitsStr1}⟩ + |{bitsStr2}⟩");
}
operation T01_MeasureParity_Test () : Unit {
// test on all basis states
for (bits in 0 .. 7) {
let bitsStr = ToString_Bitmask(bits);
TestParityOnState(StatePrep_Bitmask(_, bits), Parity(bits), $"basis state |{bitsStr}⟩");
}
// test on all superpositions of two basis states of the same parity
for (b1 in 0 .. 7) {
let bits1 = IntToBoolArray(b1);
let bitsStr1 = ToString_Bitmask(b1);
for (b2 in b1 + 1 .. 7) {
if (Parity(b1) == Parity(b2)) {
let bits2 = IntToBoolArray(b2);
let bitsStr2 = ToString_Bitmask(b2);
let p = Parity(b1);
Message($"Testing on |{bitsStr1}⟩ + |{bitsStr2}⟩ with parity {p}");
TestParityOnState(StatePrep_TwoBitmasks(_, bits1, bits2), Parity(b1), $"state |{bitsStr1}⟩ + |{bitsStr2}⟩");
}
}
}
}
//////////////////////////////////////////////////////////////////////////
// Task 02
//////////////////////////////////////////////////////////////////////////
operation AssertEqualOnZeroState (
statePrep : (Qubit[] => () : Adjoint),
testImpl : (Qubit[] => ()),
refImpl : (Qubit[] => () : Adjoint)
) : () {
body {
using (qs = Qubit[3]) {
// prepare state
statePrep(qs);
// apply operation that needs to be tested
testImpl(qs);
// apply adjoint reference operation and adjoint state prep
(Adjoint refImpl)(qs);
(Adjoint statePrep)(qs);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
statePrep : (Qubit[] => Unit : Adjoint),
testImpl : (Qubit[] => Unit),
refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
using (qs = Qubit[3]) {
// prepare state
statePrep(qs);
// apply operation that needs to be tested
testImpl(qs);
// apply adjoint reference operation and adjoint state prep
Adjoint refImpl(qs);
Adjoint statePrep(qs);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
operation StatePrep_Rotate (qs : Qubit[], alpha : Double) : () {
body {
operation StatePrep_Rotate (qs : Qubit[], alpha : Double) : Unit {
body (...) {
Ry(2.0 * alpha, qs[0]);
}
adjoint auto;
adjoint invert;
}
operation T02_Encode_Test () : () {
body {
for (i in 0..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
AssertEqualOnZeroState(StatePrep_Rotate(_, alpha), Encode, Encode_Reference);
}
operation T02_Encode_Test () : Unit {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
AssertEqualOnZeroState(StatePrep_Rotate(_, alpha), Encode, Encode_Reference);
}
}
//////////////////////////////////////////////////////////////////////////
// Task 03
//////////////////////////////////////////////////////////////////////////
operation StatePrep_WithError (qs : Qubit[], alpha : Double, hasError : Bool) : () {
body {
operation StatePrep_WithError (qs : Qubit[], alpha : Double, hasError : Bool) : Unit {
body (...) {
StatePrep_Rotate(qs, alpha);
Encode_Reference(qs);
if (hasError) {
X(qs[0]);
}
}
adjoint auto;
adjoint invert;
}
operation T03_DetectErrorOnLeftQubit_Test () : () {
body {
using (register = Qubit[3]) {
for (i in 0..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
StatePrep_WithError(register, alpha, false);
AssertResultEqual(DetectErrorOnLeftQubit(register), Zero, "Failed on a state without X error.");
(Adjoint StatePrep_WithError)(register, alpha, false);
AssertAllZero(register);
StatePrep_WithError(register, alpha, true);
AssertResultEqual(DetectErrorOnLeftQubit(register), One, "Failed on a state with X error.");
(Adjoint StatePrep_WithError)(register, alpha, true);
AssertAllZero(register);
}
operation T03_DetectErrorOnLeftQubit_Test () : Unit {
using (register = Qubit[3]) {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
StatePrep_WithError(register, alpha, false);
AssertResultEqual(DetectErrorOnLeftQubit(register), Zero, "Failed on a state without X error.");
Adjoint StatePrep_WithError(register, alpha, false);
AssertAllZero(register);
StatePrep_WithError(register, alpha, true);
AssertResultEqual(DetectErrorOnLeftQubit(register), One, "Failed on a state with X error.");
Adjoint StatePrep_WithError(register, alpha, true);
AssertAllZero(register);
}
}
}
//////////////////////////////////////////////////////////////////////////
// Task 04
//////////////////////////////////////////////////////////////////////////
operation BindErrorCorrectionRoundImpl (
encoder : (Qubit[] => () : Adjoint),
error : Pauli[],
logicalOp : (Qubit[] => ()),
correction : (Qubit[] => ()),
dataRegister : Qubit[]
) : () {
body {
using (auxiliary = Qubit[2]) {
let register = dataRegister + auxiliary;
// encode the logical qubit (dataRegister) into physical representation (register)
encoder(register);
// apply error (or no error)
ApplyPauli(error, register);
// perform logical operation on (possibly erroneous) state
logicalOp(register);
// apply correction to get the state back to correct one
correction(register);
// apply decoding to get back to 1-qubit state
(Adjoint encoder)(register);
AssertAllZero(auxiliary);
}
encoder : (Qubit[] => Unit : Adjoint),
error : Pauli[],
logicalOp : (Qubit[] => Unit),
correction : (Qubit[] => Unit),
dataRegister : Qubit[]) : Unit {
using (auxiliary = Qubit[2]) {
let register = dataRegister + auxiliary;
// encode the logical qubit (dataRegister) into physical representation (register)
encoder(register);
// apply error (or no error)
ApplyPauli(error, register);
// perform logical operation on (possibly erroneous) state
logicalOp(register);
// apply correction to get the state back to correct one
correction(register);
// apply decoding to get back to 1-qubit state
Adjoint encoder(register);
AssertAllZero(auxiliary);
}
}
function BindErrorCorrectionRound (
encoder : (Qubit[] => () : Adjoint),
error : Pauli[],
logicalOp : (Qubit[] => ()),
correction : (Qubit[] => ())
) : (Qubit[] => ()) {
encoder : (Qubit[] => Unit : Adjoint),
error : Pauli[],
logicalOp : (Qubit[] => Unit),
correction : (Qubit[] => Unit)) : (Qubit[] => Unit) {
return BindErrorCorrectionRoundImpl(encoder, error, logicalOp, correction, _);
}
// list of errors which can be corrected by the code (the first element corresponds to no error)
function PauliErrors() : Pauli[][] {
return [
[PauliI; PauliI; PauliI];
[PauliX; PauliI; PauliI];
[PauliI; PauliX; PauliI];
[PauliI; PauliI; PauliX]
];
function PauliErrors () : Pauli[][] {
return [[PauliI, PauliI, PauliI],
[PauliX, PauliI, PauliI],
[PauliI, PauliX, PauliI],
[PauliI, PauliI, PauliX]];
}
operation T04_CorrectErrorOnLeftQubit_Test () : () {
body {
let partialBind =
BindErrorCorrectionRound(Encode_Reference, _, NoOp, CorrectErrorOnLeftQubit);
let errors = PauliErrors();
for (idxError in 0..1) {
AssertOperationsEqualReferenced(partialBind(errors[idxError]), NoOp, 1);
}
operation T04_CorrectErrorOnLeftQubit_Test () : Unit {
let partialBind = BindErrorCorrectionRound(Encode_Reference, _, NoOp<Qubit[]>, CorrectErrorOnLeftQubit);
let errors = PauliErrors();
for (idxError in 0 .. 1) {
AssertOperationsEqualReferenced(partialBind(errors[idxError]), NoOp<Qubit[]>, 1);
}
}
//////////////////////////////////////////////////////////////////////////
// Task 05
//////////////////////////////////////////////////////////////////////////
operation T05_DetectErrorOnAnyQubit_Test () : () {
body {
let errors = PauliErrors();
using (register = Qubit[3]) {
for (idxError in 0..Length(errors) - 1) {
let θ = RandomReal(12);
let statePrep = BindA([H; Rz(θ, _)]);
mutable errorStr = "no error";
if (idxError > 0) {
set errorStr = $"error on qubit {idxError}";
}
Message($"Testing with {errorStr}.");
statePrep(Head(register));
Encode_Reference(register);
ApplyPauli(errors[idxError], register);
AssertIntEqual(DetectErrorOnAnyQubit(register), idxError, $"Failed on state with {errorStr}.");
ApplyPauli(errors[idxError], register);
(Adjoint Encode_Reference)(register);
(Adjoint statePrep)(Head(register));
AssertAllZero(register);
operation T05_DetectErrorOnAnyQubit_Test () : Unit {
let errors = PauliErrors();
using (register = Qubit[3]) {
for (idxError in 0 .. Length(errors) - 1) {
let θ = RandomReal(12);
let statePrep = BindCA([H, Rz(θ, _)]);
mutable errorStr = "no error";
if (idxError > 0) {
set errorStr = $"error on qubit {idxError}";
}
Message($"Testing with {errorStr}.");
statePrep(Head(register));
Encode_Reference(register);
ApplyPauli(errors[idxError], register);
AssertIntEqual(DetectErrorOnAnyQubit(register), idxError, $"Failed on state with {errorStr}.");
ApplyPauli(errors[idxError], register);
Adjoint Encode_Reference(register);
Adjoint statePrep(Head(register));
AssertAllZero(register);
}
}
}
//////////////////////////////////////////////////////////////////////////
// Task 06
//////////////////////////////////////////////////////////////////////////
operation T06_CorrectErrorOnAnyQubit_Test () : () {
body {
let partialBind =
BindErrorCorrectionRound(Encode_Reference, _, NoOp, CorrectErrorOnAnyQubit);
let errors = PauliErrors();
for (idxError in 0..Length(errors) - 1) {
Message($"Task 06: Testing on {errors[idxError]}...");
AssertOperationsEqualReferenced(partialBind(errors[idxError]), NoOp, 1);
}
operation T06_CorrectErrorOnAnyQubit_Test () : Unit {
let partialBind = BindErrorCorrectionRound(Encode_Reference, _, NoOp<Qubit[]>, CorrectErrorOnAnyQubit);
let errors = PauliErrors();
for (idxError in 0 .. Length(errors) - 1) {
Message($"Task 06: Testing on {errors[idxError]}...");
AssertOperationsEqualReferenced(partialBind(errors[idxError]), NoOp<Qubit[]>, 1);
}
}
//////////////////////////////////////////////////////////////////////////
// Task 07
//////////////////////////////////////////////////////////////////////////
operation T07_LogicalX_Test () : () {
body {
let partialBind =
BindErrorCorrectionRound(Encode_Reference, _, LogicalX, CorrectErrorOnAnyQubit_Reference);
let errors = PauliErrors();
for (idxError in 0..Length(errors) - 1) {
Message($"Task 07: Testing on {errors[idxError]}...");
AssertOperationsEqualReferenced(partialBind(errors[idxError]), ApplyPauli([PauliX], _), 1);
}
operation T07_LogicalX_Test () : Unit {
let partialBind = BindErrorCorrectionRound(Encode_Reference, _, LogicalX, CorrectErrorOnAnyQubit_Reference);
let errors = PauliErrors();
for (idxError in 0 .. Length(errors) - 1) {
Message($"Task 07: Testing on {errors[idxError]}...");
AssertOperationsEqualReferenced(partialBind(errors[idxError]), ApplyPauli([PauliX], _), 1);
}
}
//////////////////////////////////////////////////////////////////////////
// Task 08
//////////////////////////////////////////////////////////////////////////
operation T08_LogicalZ_Test () : () {
body {
let partialBind =
BindErrorCorrectionRound(Encode_Reference, _, LogicalZ, CorrectErrorOnAnyQubit_Reference);
let errors = PauliErrors();
for (idxError in 0..Length(errors) - 1) {
Message($"Task 08: Testing on {errors[idxError]}...");
AssertOperationsEqualReferenced(partialBind(errors[idxError]), ApplyToEachA(Z, _), 1);
}
operation T08_LogicalZ_Test () : Unit {
let partialBind = BindErrorCorrectionRound(Encode_Reference, _, LogicalZ, CorrectErrorOnAnyQubit_Reference);
let errors = PauliErrors();
for (idxError in 0 .. Length(errors) - 1) {
Message($"Task 08: Testing on {errors[idxError]}...");
AssertOperationsEqualReferenced(partialBind(errors[idxError]), ApplyToEachA(Z, _), 1);
}
}
}
}

Просмотреть файл

@ -1,139 +1,139 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.SimonsAlgorithm
{
namespace Quantum.Kata.SimonsAlgorithm {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Part I. Oracles
//////////////////////////////////////////////////////////////////
// Task 1.1. f(x) = 𝑥₀ ⊕ ... ⊕ xₙ₋₁ (parity of the number of bits set to 1)
operation Oracle_CountBits_Reference (x : Qubit[], y : Qubit) : ()
{
body
{
operation Oracle_CountBits_Reference (x : Qubit[], y : Qubit) : Unit {
body (...) {
let N = Length(x);
for (i in 0..N-1)
{
for (i in 0 .. N - 1) {
CNOT(x[i], y);
}
}
adjoint auto;
adjoint invert;
}
// Task 1.2. Bitwise right shift
operation Oracle_BitwiseRightShift_Reference(x : Qubit[], y : Qubit[]) : ()
{
body {
operation Oracle_BitwiseRightShift_Reference (x : Qubit[], y : Qubit[]) : Unit {
body (...) {
let N = Length(x);
for(i in 1..N-1)
{
CNOT(x[i-1], y[i]);
for (i in 1 .. N - 1) {
CNOT(x[i - 1], y[i]);
}
}
adjoint auto;
adjoint invert;
}
// Task 1.3. Linear operator
operation Oracle_OperatorOutput_Reference (x : Qubit[], y : Qubit, A : Int[]) : ()
{
body
{
operation Oracle_OperatorOutput_Reference (x : Qubit[], y : Qubit, A : Int[]) : Unit {
body (...) {
let N = Length(x);
for (i in 0..N-1)
{
if (A[i] == 1)
{
for (i in 0 .. N - 1) {
if (A[i] == 1) {
CNOT(x[i], y);
}
}
}
adjoint auto;
adjoint invert;
}
// Task 1.4. Multidimensional linear operator
operation Oracle_MultidimensionalOperatorOutput_Reference (x : Qubit[], y : Qubit[], A : Int[][]) : ()
{
body
{
operation Oracle_MultidimensionalOperatorOutput_Reference (x : Qubit[], y : Qubit[], A : Int[][]) : Unit {
body (...) {
let N1 = Length(y);
let N2 = Length(x);
for (i in 0..N1-1) {
for (j in 0..N2-1) {
if (A[i][j] == 1) {
for (i in 0 .. N1 - 1) {
for (j in 0 .. N2 - 1) {
if ((A[i])[j] == 1) {
CNOT(x[j], y[i]);
}
}
}
}
adjoint auto;
adjoint invert;
}
//////////////////////////////////////////////////////////////////
// Part II. Simon's Algorithm
//////////////////////////////////////////////////////////////////
// Task 2.1. State preparation for Simon's algorithm
operation SA_StatePrep_Reference (query : Qubit[]) : ()
{
body
{
operation SA_StatePrep_Reference (query : Qubit[]) : Unit {
body (...) {
ApplyToEachA(H, query);
}
adjoint auto;
adjoint invert;
}
// Task 2.2. Quantum part of Simon's algorithm
operation Simon_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit[]) => ())) : Int[]
{
body
{
mutable j = new Int[N];
// allocate N+N qubits
using (qs = Qubit[2*N])
{
// split allocated qubits into input register and answer register
let x = qs[0..N-1];
let y = qs[N..2*N-1];
// prepare qubits in the right state
SA_StatePrep_Reference(x);
// apply oracle
Uf(x, y);
// apply Hadamard to each qubit of the input register
ApplyToEach(H, x);
// measure all qubits of the input register;
// the result of each measurement is converted to a Bool
for (i in 0..N-1)
{
if (M(x[i]) == One)
{
set j[i] = 1;
}
operation Simon_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit[]) => Unit)) : Int[] {
mutable j = new Int[N];
// allocate N+N qubits
using (qs = Qubit[2 * N]) {
// split allocated qubits into input register and answer register
let x = qs[0 .. N - 1];
let y = qs[N .. 2 * N - 1];
// prepare qubits in the right state
SA_StatePrep_Reference(x);
// apply oracle
Uf(x, y);
// apply Hadamard to each qubit of the input register
ApplyToEach(H, x);
// measure all qubits of the input register;
// the result of each measurement is converted to a Bool
for (i in 0 .. N - 1) {
if (M(x[i]) == One) {
set j[i] = 1;
}
// before releasing the qubits make sure they are all in |0⟩ states
ResetAll(qs);
}
return j;
// before releasing the qubits make sure they are all in |0⟩ states
ResetAll(qs);
}
return j;
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.SimonsAlgorithm</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,77 +1,81 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.SimonsAlgorithm
{
namespace Quantum.Kata.SimonsAlgorithm {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Simon's Algorithm" kata is a series of exercises designed to teach a quantum algorithm for
// a problem of identifying a bit string that is implicitly defined (or, in other words, "hidden") by
// "Simon's Algorithm" kata is a series of exercises designed to teach a quantum algorithm for
// a problem of identifying a bit string that is implicitly defined (or, in other words, "hidden") by
// some oracle that satisfies certain conditions. It is arguably the most simple case of an (oracle)
// problem for which a quantum algorithm has a *provable* exponential advantage over any classical algorithm.
// problem for which a quantum algorithm has a *provable* exponential advantage over any classical algorithm.
// Each task is wrapped in one operation preceded by the description of the task. Each task (except tasks in
// which you have to write a test) has a unit test associated with it, which initially fails. Your goal is to
// fill in the blank (marked with // ... comment) with some Q# code to make the failing test pass.
//////////////////////////////////////////////////////////////////
// Part I. Oracles
//////////////////////////////////////////////////////////////////
// Task 1.1. f(x) = 𝑥₀ ⊕ ... ⊕ xₙ₋₁ (i.e., the parity of a given bit string)
// Inputs:
// 1) N qubits in an arbitrary state |x⟩
// 1) N qubits in an arbitrary state |x⟩
// 2) a qubit in an arbitrary state |y⟩
// Goal: Transform state |x, y⟩ into |x, y ⊕ x_0 ⊕ x_1 ... ⊕ x_{n-1}⟩ (⊕ is addition modulo 2).
operation Oracle_CountBits (x : Qubit[], y : Qubit) : ()
{
body
{
operation Oracle_CountBits (x : Qubit[], y : Qubit) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.2. Bitwise right shift
// Inputs:
// 1) N qubits in an arbitrary state |x⟩
// 1) N qubits in an arbitrary state |x⟩
// 2) N qubits in an arbitrary state |y⟩
// Goal: Transform state |x, y⟩ into |x, y ⊕ f(x)⟩, where f is bitwise right shift function, i.e.,
// |y ⊕ f(x)⟩ = |y_0, y_1 ⊕ x_0, y_2 ⊕ x_1, ..., y_{n-1} ⊕ x_{n-2}⟩ (⊕ is addition modulo 2).
operation Oracle_BitwiseRightShift (x : Qubit[], y : Qubit[]) : ()
{
body
{
operation Oracle_BitwiseRightShift (x : Qubit[], y : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.3. Linear operator
// Inputs:
// 1) N qubits in an arbitrary state |x⟩
// 1) N qubits in an arbitrary state |x⟩
// 2) a qubit in an arbitrary state |y⟩
// 3) a 1xN binary matrix (represented as an Int[]) describing operator A
// (see https://en.wikipedia.org/wiki/Transformation_matrix )
// Goal: Transform state |x, y⟩ into |x, y ⊕ A(x) ⟩ (⊕ is addition modulo 2).
operation Oracle_OperatorOutput (x : Qubit[], y : Qubit, A : Int[]) : ()
{
body
{
operation Oracle_OperatorOutput (x : Qubit[], y : Qubit, A : Int[]) : Unit {
body (...) {
// The following line enforces the constraint on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(A), "Arrays x and A should have the same length");
// ...
}
adjoint auto;
adjoint invert;
}
// Task 1.4. Multidimensional linear operator
// Inputs:
// 1) N1 qubits in an arbitrary state |x⟩ (input register)
@ -79,42 +83,43 @@ namespace Quantum.Kata.SimonsAlgorithm
// 3) an N2 x N1 matrix (represented as an Int[][]) describing operator A
// (see https://en.wikipedia.org/wiki/Transformation_matrix ).
// The first dimension of the matrix (rows) corresponds to the output register,
// the second dimension (columns) - the input register,
// the second dimension (columns) - the input register,
// i.e., A[r][c] (element in r-th row and c-th column) corresponds to x[c] and y[r].
// Goal: Transform state |x, y⟩ into |x, y ⊕ A(x) ⟩ (⊕ is addition modulo 2).
operation Oracle_MultidimensionalOperatorOutput (x : Qubit[], y : Qubit[], A : Int[][]) : ()
{
body
{
operation Oracle_MultidimensionalOperatorOutput (x : Qubit[], y : Qubit[], A : Int[][]) : Unit {
body (...) {
// The following lines enforce the constraints on the input arrays.
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
AssertIntEqual(Length(x), Length(A[0]), "Arrays x and A[0] should have the same length");
AssertIntEqual(Length(y), Length(A), "Arrays y and A should have the same length");
// ...
}
adjoint auto;
adjoint invert;
}
//////////////////////////////////////////////////////////////////
// Part II. Simon's Algorithm
//////////////////////////////////////////////////////////////////
// Task 2.1. State preparation for Simon's algorithm
// Inputs:
// 1) N qubits in |0⟩ state (query register)
// Goal: create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩ on query register
// (i.e. the state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N)).
operation SA_StatePrep (query : Qubit[]) : ()
{
body
{
operation SA_StatePrep (query : Qubit[]) : Unit {
body (...) {
// ...
}
adjoint auto;
adjoint invert;
}
// Task 2.2. Quantum part of Simon's algorithm
// Inputs:
// 1) the number of qubits in the input register N for the function f
@ -122,30 +127,28 @@ namespace Quantum.Kata.SimonsAlgorithm
// x is N-qubit input register, y is N-qubit answer register, and f is a function
// from N-bit strings into N-bit strings
//
// The function f is guaranteed to satisfy the following property:
// The function f is guaranteed to satisfy the following property:
// there exists some N-bit string s such that for all N-bit strings b and c (b != c)
// we have f(b) = f(c) if and only if b = c ⊕ s. In other words, f is a two-to-one function.
//
// An example of such function is bitwise right shift function from task 1.2;
// the bit string s for it is [0, ..., 0, 1].
//
//
// Output:
// Any bit string b such that Σᵢ cᵢ sᵢ = 0 modulo 2.
//
// Note that the whole algorithm will reconstruct the bit string s itself, but the quantum part of the
// algorithm will only find some vector orthogonal to the bit string s. The classical post-processing
// Note that the whole algorithm will reconstruct the bit string s itself, but the quantum part of the
// algorithm will only find some vector orthogonal to the bit string s. The classical post-processing
// part is already implemented, so once you implement the quantum part, the tests will pass.
operation Simon_Algorithm (N : Int, Uf : ((Qubit[], Qubit[]) => ())) : Int[]
{
body
{
// Declare an Int array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable b = new Int[N];
operation Simon_Algorithm (N : Int, Uf : ((Qubit[], Qubit[]) => Unit)) : Int[] {
// Declare an Int array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable b = new Int[N];
// ...
// ...
return b;
}
return b;
}
}

Просмотреть файл

@ -1,213 +1,177 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains parts of the testing harness.
// 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.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.SimonsAlgorithm
{
namespace Quantum.Kata.SimonsAlgorithm {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
// ------------------------------------------------------
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => () : Adjoint)) : ()
{
body
{
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
body (...) {
let N = Length(qs);
oracle(qs[0..N-2], qs[N-1]);
oracle(qs[0 .. N - 2], qs[N - 1]);
}
adjoint auto;
adjoint invert;
}
operation ApplyOracleWithOutputArrA (qs : Qubit[], oracle : ((Qubit[], Qubit[]) => () : Adjoint), outputSize : Int) : ()
{
body
{
operation ApplyOracleWithOutputArrA (qs : Qubit[], oracle : ((Qubit[], Qubit[]) => Unit : Adjoint), outputSize : Int) : Unit {
body (...) {
let N = Length(qs);
oracle(qs[0..N-1-outputSize], qs[N-outputSize..N-1]);
oracle(qs[0 .. (N - 1) - outputSize], qs[N - outputSize .. N - 1]);
}
adjoint auto;
adjoint invert;
}
// ------------------------------------------------------
operation AssertTwoOraclesAreEqual (
nQubits : Range,
oracle1 : ((Qubit[], Qubit) => () : Adjoint),
oracle2 : ((Qubit[], Qubit) => () : Adjoint)) : ()
{
body
{
let sol = ApplyOracleA(_, oracle1);
let refSol = ApplyOracleA(_, oracle2);
for (i in nQubits) {
AssertOperationsEqualReferenced(sol, refSol, i+1);
}
nQubits : Range,
oracle1 : ((Qubit[], Qubit) => Unit : Adjoint),
oracle2 : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
let sol = ApplyOracleA(_, oracle1);
let refSol = ApplyOracleA(_, oracle2);
for (i in nQubits) {
AssertOperationsEqualReferenced(sol, refSol, i + 1);
}
}
operation AssertTwoOraclesWithOutputArrAreEqual (
inputSize : Int,
outputSize : Int,
oracle1 : ((Qubit[], Qubit[]) => () : Adjoint),
oracle2 : ((Qubit[], Qubit[]) => () : Adjoint)) : ()
{
body
{
let sol = ApplyOracleWithOutputArrA(_, oracle1, outputSize);
let refSol = ApplyOracleWithOutputArrA(_, oracle2, outputSize);
AssertOperationsEqualReferenced(sol, refSol, inputSize + outputSize);
inputSize : Int,
outputSize : Int,
oracle1 : ((Qubit[], Qubit[]) => Unit : Adjoint),
oracle2 : ((Qubit[], Qubit[]) => Unit : Adjoint)) : Unit {
let sol = ApplyOracleWithOutputArrA(_, oracle1, outputSize);
let refSol = ApplyOracleWithOutputArrA(_, oracle2, outputSize);
AssertOperationsEqualReferenced(sol, refSol, inputSize + outputSize);
}
// ------------------------------------------------------
operation Q11_Oracle_CountBits_Test () : Unit {
AssertTwoOraclesAreEqual(1 .. 10, Oracle_CountBits, Oracle_CountBits_Reference);
}
// ------------------------------------------------------
operation Q12_Oracle_BitwiseRightShift_Test () : Unit {
for (n in 2 .. 6) {
AssertTwoOraclesWithOutputArrAreEqual(n, n, Oracle_BitwiseRightShift, Oracle_BitwiseRightShift_Reference);
}
}
// ------------------------------------------------------
operation Q11_Oracle_CountBits_Test () : ()
{
body
{
AssertTwoOraclesAreEqual(1..10, Oracle_CountBits, Oracle_CountBits_Reference);
}
}
// ------------------------------------------------------
operation Q12_Oracle_BitwiseRightShift_Test () : ()
{
body
{
for (n in 2..6) {
AssertTwoOraclesWithOutputArrAreEqual(n, n, Oracle_BitwiseRightShift, Oracle_BitwiseRightShift_Reference);
}
}
}
// ------------------------------------------------------
operation AssertTwoOraclesWithIntArrAreEqual (
A : Int[],
oracle1 : ((Qubit[], Qubit, Int[]) => () : Adjoint),
oracle2 : ((Qubit[], Qubit, Int[]) => () : Adjoint)) : ()
{
body
{
AssertTwoOraclesAreEqual(Length(A)..Length(A), oracle1(_, _, A), oracle2(_, _, A));
}
operation AssertTwoOraclesWithIntArrAreEqual (A : Int[], oracle1 : ((Qubit[], Qubit, Int[]) => Unit : Adjoint), oracle2 : ((Qubit[], Qubit, Int[]) => Unit : Adjoint)) : Unit {
AssertTwoOraclesAreEqual(Length(A) .. Length(A), oracle1(_, _, A), oracle2(_, _, A));
}
operation Q13_Oracle_OperatorOutput_Test () : ()
{
body
{
// cross-tests
// the mask for all 1's should behave the same as Oracle_CountBits
mutable A = [1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1];
let L = Length(A);
for (i in 2..L)
{
AssertTwoOraclesAreEqual(i..i, Oracle_OperatorOutput(_, _, A[0..i-1]), Oracle_OperatorOutput_Reference(_, _, A[0..i-1]));
}
set A = [1; 1; 0; 0];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
set A = [0; 0; 0; 0; 0];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
set A = [1; 0; 1; 1; 1];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
set A = [0; 1; 0; 0];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
operation Q13_Oracle_OperatorOutput_Test () : Unit {
// cross-tests
// the mask for all 1's should behave the same as Oracle_CountBits
mutable A = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let L = Length(A);
for (i in 2 .. L) {
AssertTwoOraclesAreEqual(i .. i, Oracle_OperatorOutput(_, _, A[0 .. i - 1]), Oracle_OperatorOutput_Reference(_, _, A[0 .. i - 1]));
}
}
set A = [1, 1, 0, 0];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
set A = [0, 0, 0, 0, 0];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
set A = [1, 0, 1, 1, 1];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
set A = [0, 1, 0, 0];
AssertTwoOraclesWithIntArrAreEqual(A, Oracle_OperatorOutput, Oracle_OperatorOutput_Reference);
}
// ------------------------------------------------------
operation AssertTwoOraclesWithIntMatrixAreEqual (
A : Int[][],
oracle1 : ((Qubit[], Qubit[], Int[][]) => () : Adjoint),
oracle2 : ((Qubit[], Qubit[], Int[][]) => () : Adjoint)) : ()
{
body
{
let inputSize = Length(A[0]);
let outputSize = Length(A);
AssertTwoOraclesWithOutputArrAreEqual(inputSize, outputSize, oracle1(_, _, A), oracle2(_, _, A));
}
A : Int[][],
oracle1 : ((Qubit[], Qubit[], Int[][]) => Unit : Adjoint),
oracle2 : ((Qubit[], Qubit[], Int[][]) => Unit : Adjoint)) : Unit {
let inputSize = Length(A[0]);
let outputSize = Length(A);
AssertTwoOraclesWithOutputArrAreEqual(inputSize, outputSize, oracle1(_, _, A), oracle2(_, _, A));
}
operation AssertTwoOraclesWithDifferentOutputsAreEqual (
inputSize : Int,
oracle1 : ((Qubit[], Qubit[]) => () : Adjoint),
oracle2 : ((Qubit[], Qubit) => () : Adjoint)) : ()
{
body
{
let sol = ApplyOracleWithOutputArrA(_, oracle1, 1);
let refSol = ApplyOracleA(_, oracle2);
AssertOperationsEqualReferenced(sol, refSol, inputSize+1);
}
inputSize : Int,
oracle1 : ((Qubit[], Qubit[]) => Unit : Adjoint),
oracle2 : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
let sol = ApplyOracleWithOutputArrA(_, oracle1, 1);
let refSol = ApplyOracleA(_, oracle2);
AssertOperationsEqualReferenced(sol, refSol, inputSize + 1);
}
operation Q14_Oracle_MultidimensionalOperatorOutput_Test () : Unit {
mutable A = [[1, 1], [0, 0]];
AssertTwoOraclesWithIntMatrixAreEqual(A, Oracle_MultidimensionalOperatorOutput, Oracle_MultidimensionalOperatorOutput_Reference);
set A = [[1, 0], [0, 1], [1, 1]];
AssertTwoOraclesWithIntMatrixAreEqual(A, Oracle_MultidimensionalOperatorOutput, Oracle_MultidimensionalOperatorOutput_Reference);
operation Q14_Oracle_MultidimensionalOperatorOutput_Test () : ()
{
body
{
mutable A = [[1; 1]; [0; 0]];
AssertTwoOraclesWithIntMatrixAreEqual(A, Oracle_MultidimensionalOperatorOutput, Oracle_MultidimensionalOperatorOutput_Reference);
set A = [[1; 0]; [0; 1]; [1; 1]];
AssertTwoOraclesWithIntMatrixAreEqual(A, Oracle_MultidimensionalOperatorOutput, Oracle_MultidimensionalOperatorOutput_Reference);
set A = [[0; 1; 0]; [1; 0; 1]];
AssertTwoOraclesWithIntMatrixAreEqual(A, Oracle_MultidimensionalOperatorOutput, Oracle_MultidimensionalOperatorOutput_Reference);
// cross-test for bitwise right shift oracle
set A = [[0; 0; 0; 0];
[1; 0; 0; 0];
[0; 1; 0; 0];
[0; 0; 1; 0]];
AssertTwoOraclesWithOutputArrAreEqual(4, 4, Oracle_MultidimensionalOperatorOutput(_, _, A), Oracle_BitwiseRightShift_Reference);
// cross-test for 1-dimensional output
mutable B = [1; 0; 1; 0; 1];
AssertTwoOraclesWithDifferentOutputsAreEqual(5, Oracle_MultidimensionalOperatorOutput(_, _, [B]), Oracle_OperatorOutput_Reference(_, _, B));
// cross-test for bit counting oracle
set B = [1; 1; 1; 1; 1];
AssertTwoOraclesWithDifferentOutputsAreEqual(5, Oracle_MultidimensionalOperatorOutput(_, _, [B]), Oracle_CountBits_Reference);
}
set A = [[0, 1, 0], [1, 0, 1]];
AssertTwoOraclesWithIntMatrixAreEqual(A, Oracle_MultidimensionalOperatorOutput, Oracle_MultidimensionalOperatorOutput_Reference);
// cross-test for bitwise right shift oracle
set A = [[0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]];
AssertTwoOraclesWithOutputArrAreEqual(4, 4, Oracle_MultidimensionalOperatorOutput(_, _, A), Oracle_BitwiseRightShift_Reference);
// cross-test for 1-dimensional output
mutable B = [1, 0, 1, 0, 1];
AssertTwoOraclesWithDifferentOutputsAreEqual(5, Oracle_MultidimensionalOperatorOutput(_, _, [B]), Oracle_OperatorOutput_Reference(_, _, B));
// cross-test for bit counting oracle
set B = [1, 1, 1, 1, 1];
AssertTwoOraclesWithDifferentOutputsAreEqual(5, Oracle_MultidimensionalOperatorOutput(_, _, [B]), Oracle_CountBits_Reference);
}
operation Q21_StatePrep_Test () : ()
{
body
{
for (N in 1..10) {
using (qs = Qubit[N])
{
// apply operation that needs to be tested
SA_StatePrep(qs[0..N-1]);
// apply adjoint reference operation
(Adjoint SA_StatePrep_Reference)(qs[0..N-1]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
operation Q21_StatePrep_Test () : Unit {
for (N in 1 .. 10) {
using (qs = Qubit[N]) {
// apply operation that needs to be tested
SA_StatePrep(qs[0 .. N - 1]);
// apply adjoint reference operation
Adjoint SA_StatePrep_Reference(qs[0 .. N - 1]);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
}
// ------------------------------------------------------
operation cs_helper(N: Int, Matrix: Int[][]) : (Int[], ((Qubit[], Qubit[]) => ()))
{
body
{
let Uf = Oracle_MultidimensionalOperatorOutput_Reference(_, _, Matrix);
return (Simon_Algorithm(N, Uf), Uf);
}
operation cs_helper (N : Int, Matrix : Int[][]) : (Int[], ((Qubit[], Qubit[]) => Unit)) {
let Uf = Oracle_MultidimensionalOperatorOutput_Reference(_, _, Matrix);
return (Simon_Algorithm(N, Uf), Uf);
}
}
}

Просмотреть файл

@ -1,126 +1,123 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.SuperdenseCoding
{
namespace Quantum.Kata.SuperdenseCoding {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
// Task 1. Entangled pair
operation CreateEntangledPair_Reference (qs : Qubit[]) : ()
{
body
{
// The easiest way to create an entangled pair is to start with
operation CreateEntangledPair_Reference (qs : Qubit[]) : Unit {
body (...) {
// The easiest way to create an entangled pair is to start with
// applying a Hadamard transformation to one of the qubits:
H(qs[0]);
// This has left us in state:
// ((|0⟩ + |1⟩) / sqrt(2)) ⊗ |0⟩
// Now, if we flip the second qubit conditioned on the state
// of the first one, we get that the states of the two qubits will always match.
CNOT(qs[0], qs[1]);
// So we ended up in the state:
// (|00⟩ + |11⟩) / sqrt(2)
//
// Which is the required Bell pair |Φ⁺⟩
}
adjoint auto;
adjoint invert;
}
// Task 2. Send the message (Alice's task)
operation EncodeMessageInQubit_Reference (qAlice : Qubit, message : Bool[]) : ()
{
body
{
// We are starting this step with the entangled pair in state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// By doing operations on one of those qubits,
// we can encode each of the values as a transformation:
// "00" as I and |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
// "01" as X and |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
// "10" as Z and |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
// "11" as Y and |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
// Also, since Y(q) = iX(Z(q)), we can express this shorter:
if (message[0]) { Z(qAlice); }
if (message[1]) { X(qAlice); }
operation EncodeMessageInQubit_Reference (qAlice : Qubit, message : Bool[]) : Unit {
// We are starting this step with the entangled pair in state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// By doing operations on one of those qubits,
// we can encode each of the values as a transformation:
// "00" as I and |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
// "01" as X and |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
// "10" as Z and |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
// "11" as Y and |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
// Also, since Y(q) = iX(Z(q)), we can express this shorter:
if (message[0]) {
Z(qAlice);
}
if (message[1]) {
X(qAlice);
}
}
// Task 3. Decode the message (Bob's task)
operation DecodeMessageFromQubits_Reference (qBob : Qubit, qAlice : Qubit) : Bool[]
{
body
{
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable decoded_bits = new Bool[2];
// Time to get our state back, by performing transformations as follows.
// Notice that it's important to keep the order right. The qubits that are
// subject to the Hadamard transform and the CNOT gate in the preparation
// of the pair have to match the operations below, or the order of the data
// bits will get flipped.
CNOT(qAlice, qBob);
H(qAlice);
// What is the outcome of this transformation, assuming each of the possible
// quantum states after the encoding step?
// |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2) ---> |00⟩
// |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2) ---> |01⟩
// |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2) ---> |10⟩
// |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2) ---> |11⟩
// So we can retrieve the encoded bits just by measuring.
set decoded_bits[0] = M(qAlice) == One;
set decoded_bits[1] = M(qBob) == One;
return decoded_bits;
}
operation DecodeMessageFromQubits_Reference (qBob : Qubit, qAlice : Qubit) : Bool[] {
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable decoded_bits = new Bool[2];
// Time to get our state back, by performing transformations as follows.
// Notice that it's important to keep the order right. The qubits that are
// subject to the Hadamard transform and the CNOT gate in the preparation
// of the pair have to match the operations below, or the order of the data
// bits will get flipped.
CNOT(qAlice, qBob);
H(qAlice);
// What is the outcome of this transformation, assuming each of the possible
// quantum states after the encoding step?
// |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2) ---> |00⟩
// |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2) ---> |01⟩
// |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2) ---> |10⟩
// |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2) ---> |11⟩
// So we can retrieve the encoded bits just by measuring.
set decoded_bits[0] = M(qAlice) == One;
set decoded_bits[1] = M(qBob) == One;
return decoded_bits;
}
// Task 4. Superdense coding protocol end-to-end
operation SuperdenseCodingProtocol_Reference (message : Bool[]) : Bool[]
{
body
{
mutable decoded_bits = new Bool[2];
// Get a temporary qubit register for the protocol run.
using (qs = Qubit[2])
{
// STEP 1:
// Start by creating an entangled pair of qubits.
CreateEntangledPair_Reference(qs);
// Alice and Bob receive one half of the pair each.
// STEP 2:
// Alice encodes the pair of bits in the qubit she received.
EncodeMessageInQubit_Reference(qs[0], message);
// Alice sends her qubit to Bob.
// STEP 3:
// Bob receives the qubit from Alice and can now
// manipulate and measure both qubits to get the encoded data.
set decoded_bits = DecodeMessageFromQubits_Reference(qs[1], qs[0]);
// Make sure that we return qubits back in 0 state.
ResetAll(qs);
}
return decoded_bits;
operation SuperdenseCodingProtocol_Reference (message : Bool[]) : Bool[] {
mutable decoded_bits = new Bool[2];
// Get a temporary qubit register for the protocol run.
using (qs = Qubit[2]) {
// STEP 1:
// Start by creating an entangled pair of qubits.
CreateEntangledPair_Reference(qs);
// Alice and Bob receive one half of the pair each.
// STEP 2:
// Alice encodes the pair of bits in the qubit she received.
EncodeMessageInQubit_Reference(qs[0], message);
// Alice sends her qubit to Bob.
// STEP 3:
// Bob receives the qubit from Alice and can now
// manipulate and measure both qubits to get the encoded data.
set decoded_bits = DecodeMessageFromQubits_Reference(qs[1], qs[0]);
// Make sure that we return qubits back in 0 state.
ResetAll(qs);
}
return decoded_bits;
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.SuperdenseCoding</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,65 +1,60 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.SuperdenseCoding
{
namespace Quantum.Kata.SuperdenseCoding {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
///////////////////////////////////////////////////////////////////////
// //
// Superdense Coding Kata : Share 2 bits for the price of 1 qubit! //
// //
///////////////////////////////////////////////////////////////////////
// "Superdense Coding" quantum kata is a series of exercises designed
// "Superdense Coding" quantum kata is a series of exercises designed
// to get you familiar with programming in Q#.
// It covers the superdense coding protocol which allows to transmit
// two bits of classical information by sending just one qubit
// It covers the superdense coding protocol which allows to transmit
// two bits of classical information by sending just one qubit
// using previously shared quantum entanglement.
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//
// Each task defines an operation that can be used in subsequent tasks to simplify implementations
// and build on existing code.
// We split the superdense coding protocol into several steps, following the description at
// https://en.wikipedia.org/wiki/Superdense_coding :
// * Preparation (creating the entangled pair of qubits that are sent to Alice and Bob).
// * Encoding the message (Alice's task): Encoding the classical bits of the message
// into the state of Alice's qubit which then is sent to Bob.
// * Decoding the message (Bob's task): Using Bob's original qubit and the qubit he
// * Decoding the message (Bob's task): Using Bob's original qubit and the qubit he
// received from Alice to decode the classical message sent.
// Finally, we compose those steps into the complete superdense coding protocol.
// Task 1. Entangled pair
// Input: An array of two qubits in the |00⟩ state.
// Goal: Create a Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2) on these qubits.
operation CreateEntangledPair (qs : Qubit[]) : ()
{
body
{
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
operation CreateEntangledPair (qs : Qubit[]) : Unit {
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
// ...
}
// ...
}
// Task 2. Send the message (Alice's task)
// Encode the message (classical bits) in the state of Alice's qubit.
// Inputs:
// 1) Alice's part of the entangled pair of qubits qAlice.
// 2) two classical bits, stored in an array.
// Goal: Transform the input qubit to encode the two classical bits.
operation EncodeMessageInQubit (qAlice : Qubit, message : Bool[]) : ()
{
body
{
operation EncodeMessageInQubit (qAlice : Qubit, message : Bool[]) : Unit {
// Hint: manipulate Alice's half of the entangled pair
// to change the joint state of the two qubits to one of the following four states
// based on the value of message:
@ -69,9 +64,9 @@ namespace Quantum.Kata.SuperdenseCoding
// [1; 1]: |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
// ...
}
}
// Task 3. Decode the message (Bob's task)
// Decode the message using the qubit received from Alice.
// Inputs:
@ -79,35 +74,30 @@ namespace Quantum.Kata.SuperdenseCoding
// 2) qubit received from Alice qAlice.
// Goal: Retrieve two bits of classic data from the qubits.
// The state of the qubits in the end of the operation doesn't matter.
operation DecodeMessageFromQubits (qBob : Qubit, qAlice : Qubit) : Bool[]
{
body
{
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable decoded_bits = new Bool[2];
operation DecodeMessageFromQubits (qBob : Qubit, qAlice : Qubit) : Bool[] {
// Declare a Bool array in which the result will be stored;
// the array has to be mutable to allow updating its elements.
mutable decoded_bits = new Bool[2];
// ...
// ...
return decoded_bits;
}
return decoded_bits;
}
// Task 4. Superdense coding protocol end-to-end
// Put together the steps performed in tasks 1-3 to implement the full superdense coding protocol.
// Input: Two classical bits
// Goal: Prepare an EPR Pair, encode the two classical bits in the
// state of the pair by applying quantum gates to one member of the pair,
// and decode the two classical gates from the state of the pair
operation SuperdenseCodingProtocol (message : Bool[]) : Bool[]
{
body
{
mutable decoded_bits = new Bool[2];
operation SuperdenseCodingProtocol (message : Bool[]) : Bool[] {
mutable decoded_bits = new Bool[2];
// ...
// ...
return decoded_bits;
}
return decoded_bits;
}
}

Просмотреть файл

@ -1,116 +1,92 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.SuperdenseCoding
{
namespace Quantum.Kata.SuperdenseCoding {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
// ------------------------------------------------------
operation AssertEqualOnZeroState (N : Int, taskImpl : (Qubit[] => ()), refImpl : (Qubit[] => () : Adjoint)) : ()
{
body
{
using (qs = Qubit[N])
{
// apply operation that needs to be tested
taskImpl(qs);
// apply adjoint reference operation and check that the result is |0^N⟩
(Adjoint refImpl)(qs);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
operation AssertEqualOnZeroState (N : Int, taskImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
using (qs = Qubit[N]) {
// apply operation that needs to be tested
taskImpl(qs);
// apply adjoint reference operation and check that the result is |0^N⟩
Adjoint refImpl(qs);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
operation T1_CreateEntangledPair_Test () : ()
{
body
{
// We only check for 2 qubits.
AssertEqualOnZeroState(2, CreateEntangledPair, CreateEntangledPair_Reference);
}
operation T1_CreateEntangledPair_Test () : Unit {
// We only check for 2 qubits.
AssertEqualOnZeroState(2, CreateEntangledPair, CreateEntangledPair_Reference);
}
// ------------------------------------------------------
// Helper operation that runs superdense coding protocol using two building blocks
// specified as first two parameters.
operation ComposeProtocol (
encodeOp : ((Qubit, Bool[]) => ()),
decodeOp : ((Qubit, Qubit) => Bool[]),
message : Bool[]
) : Bool[]
{
body
{
mutable result = new Bool[2];
using (qs = Qubit[2]) {
CreateEntangledPair_Reference(qs);
encodeOp(qs[0], message);
set result = decodeOp(qs[1], qs[0]);
// Make sure that we return qubits back in 0 state.
ResetAll(qs);
}
return result;
operation ComposeProtocol (encodeOp : ((Qubit, Bool[]) => Unit), decodeOp : ((Qubit, Qubit) => Bool[]), message : Bool[]) : Bool[] {
mutable result = new Bool[2];
using (qs = Qubit[2]) {
CreateEntangledPair_Reference(qs);
encodeOp(qs[0], message);
set result = decodeOp(qs[1], qs[0]);
// Make sure that we return qubits back in 0 state.
ResetAll(qs);
}
return result;
}
// ------------------------------------------------------
// Helper operation that runs superdense coding protocol (specified by protocolOp)
// on all possible input values and verifies that decoding result matches the inputs
operation TestProtocol (
protocolOp : ((Bool[]) => Bool[])
) : ()
{
body
{
mutable data = new Bool[2];
// Loop over the 4 possible combinations of two bits
for (n in 0..3)
{
set data[0] = 1 == (n / 2);
set data[1] = 1 == (n % 2);
for (iter in 1..100) {
let result = protocolOp(data);
// Now test if the bits were transfered correctly.
AssertBoolArrayEqual(result, data, $"The message {data} was transfered incorrectly as {result}" );
}
operation TestProtocol (protocolOp : (Bool[] => Bool[])) : Unit {
mutable data = new Bool[2];
// Loop over the 4 possible combinations of two bits
for (n in 0 .. 3) {
set data[0] = 1 == n / 2;
set data[1] = 1 == n % 2;
for (iter in 1 .. 100) {
let result = protocolOp(data);
// Now test if the bits were transfered correctly.
AssertBoolArrayEqual(result, data, $"The message {data} was transfered incorrectly as {result}");
}
}
}
operation T2_EncodeMessageInQubit_Test () : ()
{
body
{
TestProtocol(ComposeProtocol(EncodeMessageInQubit, DecodeMessageFromQubits_Reference, _));
}
operation T2_EncodeMessageInQubit_Test () : Unit {
TestProtocol(ComposeProtocol(EncodeMessageInQubit, DecodeMessageFromQubits_Reference, _));
}
operation T3_DecodeMessageFromQubits_Test () : ()
{
body
{
TestProtocol(ComposeProtocol(EncodeMessageInQubit_Reference, DecodeMessageFromQubits, _));
}
operation T3_DecodeMessageFromQubits_Test () : Unit {
TestProtocol(ComposeProtocol(EncodeMessageInQubit_Reference, DecodeMessageFromQubits, _));
}
operation T4_SuperdenseCodingProtocol_Test () : ()
{
body
{
TestProtocol(SuperdenseCodingProtocol);
}
operation T4_SuperdenseCodingProtocol_Test () : Unit {
TestProtocol(SuperdenseCodingProtocol);
}
}
}

Просмотреть файл

@ -1,114 +1,121 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs 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.Superposition
{
namespace Quantum.Kata.Superposition {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
// Task 1. Plus state
// Input: a qubit in |0⟩ state (stored in an array of length 1).
// Goal: create a |+⟩ state on this qubit (|+⟩ = (|0⟩ + |1⟩) / sqrt(2)).
operation PlusState_Reference (qs : Qubit[]) : ()
{
body
{
operation PlusState_Reference (qs : Qubit[]) : Unit {
body (...) {
H(qs[0]);
}
adjoint auto;
adjoint invert;
}
// Task 2. Minus state
// Input: a qubit in |0⟩ state (stored in an array of length 1).
// Goal: create a |-⟩ state on this qubit (|-⟩ = (|0⟩ - |1⟩) / sqrt(2)).
operation MinusState_Reference (qs : Qubit[]) : ()
{
body
{
operation MinusState_Reference (qs : Qubit[]) : Unit {
body (...) {
X(qs[0]);
H(qs[0]);
}
adjoint auto;
adjoint invert;
}
// Task 3. Unequal superposition
// Inputs:
// 1) a qubit in |0⟩ state (stored in an array of length 1).
// 2) angle alpha, in radians, represented as Double
// Goal: create a cos(alpha) * |0⟩ + sin(alpha) * |1⟩ state on this qubit.
operation UnequalSuperposition_Reference (qs : Qubit[], alpha : Double) : ()
{
body
{
operation UnequalSuperposition_Reference (qs : Qubit[], alpha : Double) : Unit {
body (...) {
// Hint: Experiment with rotation gates from Microsoft.Quantum.Primitive
Ry(2.0 * alpha, qs[0]);
}
adjoint auto;
adjoint invert;
}
// Task 4. Superposition of all basis vectors on two qubits
operation AllBasisVectors_TwoQubits_Reference (qs : Qubit[]) : ()
{
body
{
operation AllBasisVectors_TwoQubits_Reference (qs : Qubit[]) : Unit {
body (...) {
// Since a Hadamard gate will change |0⟩ into |+⟩ = (|0⟩ + |1⟩)/sqrt(2)
// And the desired state is just a tensor product |+⟩|+⟩, we can apply
// a Hadamard transformation to each qubit.
H(qs[0]);
H(qs[1]);
}
adjoint auto;
adjoint invert;
}
// Task 5. Superposition of basis vectors with phases
operation AllBasisVectorsWithPhases_TwoQubits_Reference (qs : Qubit[]) : ()
{
body
{
operation AllBasisVectorsWithPhases_TwoQubits_Reference (qs : Qubit[]) : Unit {
body (...) {
// Question:
// Is this state separable?
// Answer:
// Yes. It is. We can see that:
// ((|0⟩ - |1⟩) / sqrt(2)) ⊗ ((|0⟩ + i*|1⟩) / sqrt(2)) is equal to the desired
// state, so we can create it by doing operations on each qubit independently.
// We can see that the first qubit is in state |-⟩ and the second in state |i⟩,
// We can see that the first qubit is in state |-⟩ and the second in state |i⟩,
// so the transformations that we need are:
// Qubit 0 is taken into |+⟩ and then z-rotated into |-⟩.
H(qs[0]);
Z(qs[0]);
// Qubit 1 is taken into |+⟩ and then z-rotated into |i⟩.
H(qs[1]);
S(qs[1]);
}
adjoint auto;
adjoint invert;
}
// Task 6. Bell state
// Input: two qubits in |00⟩ state (stored in an array of length 2).
// Goal: create a Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2) on these qubits.
operation BellState_Reference (qs : Qubit[]) : ()
{
body
{
operation BellState_Reference (qs : Qubit[]) : Unit {
body (...) {
H(qs[0]);
CNOT(qs[0], qs[1]);
}
adjoint auto;
adjoint invert;
}
// Task 7. All Bell states
// Inputs:
// 1) two qubits in |00⟩ state (stored in an array of length 2)
@ -118,12 +125,12 @@ namespace Quantum.Kata.Superposition
// 1: |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
// 2: |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
// 3: |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
operation AllBellStates_Reference (qs : Qubit[], index : Int) : ()
{
body
{
operation AllBellStates_Reference (qs : Qubit[], index : Int) : Unit {
body (...) {
H(qs[0]);
CNOT(qs[0], qs[1]);
// now we have |00⟩ + |11⟩ - modify it based on index arg
if (index % 2 == 1) {
// negative phase
@ -133,39 +140,44 @@ namespace Quantum.Kata.Superposition
X(qs[1]);
}
}
adjoint auto;
adjoint invert;
}
// Task 8. Greenberger–Horne–Zeilinger state
// Input: N qubits in |0...0⟩ state.
// Goal: create a GHZ state (|0...0⟩ + |1...1⟩) / sqrt(2) on these qubits.
operation GHZ_State_Reference (qs : Qubit[]) : ()
{
body
{
operation GHZ_State_Reference (qs : Qubit[]) : Unit {
body (...) {
H(qs[0]);
for (i in 1 .. Length(qs)-1) {
for (i in 1 .. Length(qs) - 1) {
CNOT(qs[0], qs[i]);
}
}
adjoint auto;
adjoint invert;
}
// Task 9. Superposition of all basis vectors
// Input: N qubits in |0...0⟩ state.
// Goal: create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩
// (i.e. state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N) ).
operation AllBasisVectorsSuperposition_Reference (qs : Qubit[]) : ()
{
body
{
for (i in 0 .. Length(qs)-1) {
operation AllBasisVectorsSuperposition_Reference (qs : Qubit[]) : Unit {
body (...) {
for (i in 0 .. Length(qs) - 1) {
H(qs[i]);
}
}
adjoint auto;
adjoint invert;
}
// Task 10. Superposition of |0...0⟩ and given bit string
// Inputs:
// 1) N qubits in |0...0⟩ state
@ -174,61 +186,61 @@ namespace Quantum.Kata.Superposition
// Bit values false and true correspond to |0⟩ and |1⟩ states.
// You are guaranteed that the qubit array and the bit string have the same length.
// You are guaranteed that the first bit of the bit string is true.
// Example: for bit string = [true; false] the qubit state required is (|00⟩ + |10⟩) / sqrt(2).
operation ZeroAndBitstringSuperposition_Reference (qs : Qubit[], bits : Bool[]) : ()
{
body
{
// Example: for bit string = [true, false] the qubit state required is (|00⟩ + |10⟩) / sqrt(2).
operation ZeroAndBitstringSuperposition_Reference (qs : Qubit[], bits : Bool[]) : Unit {
body (...) {
AssertIntEqual(Length(bits), Length(qs), "Arrays should have the same length");
AssertBoolEqual(bits[0], true, "First bit of the input bit string should be set to true");
// Hadamard first qubit
H(qs[0]);
// iterate through the bit string and CNOT to qubits corresponding to true bits
for (i in 1..Length(qs)-1) {
for (i in 1 .. Length(qs) - 1) {
if (bits[i]) {
CNOT(qs[0], qs[i]);
}
}
}
adjoint auto;
adjoint invert;
}
// Task 11. Superposition of two bit strings
// Inputs:
// 1) N qubits in |0...0⟩ state
// 2) two bit string represented as Bool[]s
// Goal: create an equal superposition of two basis states given by the bit strings.
// Bit values false and true correspond to |0⟩ and |1⟩ states.
// Example: for bit strings [false; true; false] and [false; false; true]
// Example: for bit strings [false, true, false] and [false, false, true]
// the qubit state required is (|010⟩ + |001⟩) / sqrt(2).
// You are guaranteed that the two bit strings will be different.
// helper function for TwoBitstringSuperposition_Reference
function FindFirstDiff_Reference (bits1 : Bool[], bits2 : Bool[]) : Int
{
function FindFirstDiff_Reference (bits1 : Bool[], bits2 : Bool[]) : Int {
mutable firstDiff = -1;
for (i in 0 .. Length(bits1)-1) {
for (i in 0 .. Length(bits1) - 1) {
if (bits1[i] != bits2[i] && firstDiff == -1) {
set firstDiff = i;
}
}
return firstDiff;
}
operation TwoBitstringSuperposition_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : ()
{
body
{
operation TwoBitstringSuperposition_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Unit {
body (...) {
// find the index of the first bit at which the bit strings are different
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
// Hadamard corresponding qubit to create superposition
H(qs[firstDiff]);
// iterate through the bit strings again setting the final state of qubits
for (i in 0 .. Length(qs)-1) {
for (i in 0 .. Length(qs) - 1) {
if (bits1[i] == bits2[i]) {
// if two bits are the same apply X or nothing
if (bits1[i]) {
@ -245,55 +257,61 @@ namespace Quantum.Kata.Superposition
}
}
}
adjoint auto;
adjoint invert;
}
// Task 12. W state on 2^k qubits
// Input: N = 2^k qubits in |0...0⟩ state.
// Goal: create a W state (https://en.wikipedia.org/wiki/W_state) on these qubits.
// W state is an equal superposition of all basis states on N qubits of Hamming weight 1.
// Example: for N = 4, W state is (|1000⟩ + |0100⟩ + |0010⟩ + |0001⟩) / 2.
operation WState_PowerOfTwo_Reference (qs : Qubit[]) : ()
{
body
{
operation WState_PowerOfTwo_Reference (qs : Qubit[]) : Unit {
body (...) {
let N = Length(qs);
if (N == 1) {
// base of recursion: |1⟩
X(qs[0]);
} else {
let K = N / 2;
// create W state on the first K qubits
WState_PowerOfTwo_Reference(qs[0..K-1]);
WState_PowerOfTwo_Reference(qs[0 .. K - 1]);
// the next K qubits are in |0...0⟩ state
// allocate ancilla in |+⟩ state
using (anc = Qubit[1]) {
H(anc[0]);
for (i in 0..K-1) {
(Controlled SWAP)(anc, (qs[i], qs[i+K]));
for (i in 0 .. K - 1) {
Controlled SWAP(anc, (qs[i], qs[i + K]));
}
for (i in K..N-1) {
for (i in K .. N - 1) {
CNOT(qs[i], anc[0]);
}
}
}
}
adjoint auto;
adjoint invert;
}
// Task 13. W state on arbitrary number of qubits
// Input: N qubits in |0...0⟩ state (N is not necessarily a power of 2).
// Goal: create a W state (https://en.wikipedia.org/wiki/W_state) on these qubits.
// W state is an equal superposition of all basis states on N qubits of Hamming weight 1.
// Example: for N = 3, W state is (|100⟩ + |010⟩ + |001⟩) / sqrt(3).
// general solution based on rotations and recursive application of controlled generation routine
operation WState_Arbitrary_Reference (qs : Qubit[]) : ()
{
body
{
operation WState_Arbitrary_Reference (qs : Qubit[]) : Unit {
body (...) {
let N = Length(qs);
if (N == 1) {
// base case of recursion: |1⟩
X(qs[0]);
@ -303,59 +321,62 @@ namespace Quantum.Kata.Superposition
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
let theta = ArcSin(1.0 / Sqrt(ToDouble(N)));
Ry(2.0 * theta, qs[0]);
// do a zero-controlled W-state generation for qubits 1..N-1
X(qs[0]);
(Controlled WState_Arbitrary_Reference)(qs[0..0], qs[1..N-1]);
Controlled WState_Arbitrary_Reference(qs[0 .. 0], qs[1 .. N - 1]);
X(qs[0]);
}
}
adjoint auto;
controlled auto;
adjoint controlled auto;
adjoint invert;
controlled distribute;
controlled adjoint distribute;
}
// solution based on generation for 2^k and post-selection using measurements
operation WState_Arbitrary_Postselect (qs : Qubit[]) : ()
{
body
{
let N = Length(qs);
if (N == 1) {
// base case of recursion: |1⟩
X(qs[0]);
} else {
// find the smallest power of 2 which is greater than or equal to N
// as a hack, we know we're not doing it on more than 64 qubits
mutable P = 1;
for (i in 1..6) {
if (P < N) {
set P = P * 2;
}
operation WState_Arbitrary_Postselect (qs : Qubit[]) : Unit {
let N = Length(qs);
if (N == 1) {
// base case of recursion: |1⟩
X(qs[0]);
} else {
// find the smallest power of 2 which is greater than or equal to N
// as a hack, we know we're not doing it on more than 64 qubits
mutable P = 1;
for (i in 1 .. 6) {
if (P < N) {
set P = P * 2;
}
if (P == N) {
// prepare as a power of 2 (previous task)
WState_PowerOfTwo_Reference(qs);
} else {
// allocate extra qubits
using (ans = Qubit[P-N]) {
let all_qubits = qs + ans;
repeat {
// prepare state W_P on original + ancilla qubits
WState_PowerOfTwo_Reference(all_qubits);
// measure ancilla qubits; if all of the results are Zero, we get the right state on main qubits
mutable allZeros = true;
for (i in 0..P-N-1) {
set allZeros = allZeros && IsResultZero(M(ans[i]));
}
} until allZeros
fixup {
ResetAll(ans);
}
if (P == N) {
// prepare as a power of 2 (previous task)
WState_PowerOfTwo_Reference(qs);
} else {
// allocate extra qubits
using (ans = Qubit[P - N]) {
let all_qubits = qs + ans;
repeat {
// prepare state W_P on original + ancilla qubits
WState_PowerOfTwo_Reference(all_qubits);
// measure ancilla qubits; if all of the results are Zero, we get the right state on main qubits
mutable allZeros = true;
for (i in 0 .. (P - N) - 1) {
set allZeros = allZeros && IsResultZero(M(ans[i]));
}
}
until (allZeros)
fixup {
ResetAll(ans);
}
}
}
}
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.Superposition</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,118 +1,101 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.Superposition
{
namespace Quantum.Kata.Superposition {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Superposition" quantum kata is a series of exercises designed
// "Superposition" quantum kata is a series of exercises designed
// to get you familiar with programming in Q#.
// It covers the following topics:
// - basic single-qubit and multi-qubit gates,
// - superposition,
// - flow control and recursion in Q#.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
// Task 1. Plus state
// Input: a qubit in |0⟩ state (stored in an array of length 1).
// Goal: create a |+⟩ state on this qubit (|+⟩ = (|0⟩ + |1⟩) / sqrt(2)).
operation PlusState (qs : Qubit[]) : ()
{
body
{
// Hadamard gate H will convert |0⟩ state to |+⟩ state.
// The first qubit of the array can be accessed as qs[0].
// Type the following: H(qs[0]);
// Then rebuild the project and rerun the tests - T01_PlusState_Test should now pass!
operation PlusState (qs : Qubit[]) : Unit {
// Hadamard gate H will convert |0⟩ state to |+⟩ state.
// The first qubit of the array can be accessed as qs[0].
// Type the following: H(qs[0]);
// Then rebuild the project and rerun the tests - T01_PlusState_Test should now pass!
// ...
}
// ...
}
// Task 2. Minus state
// Input: a qubit in |0⟩ state (stored in an array of length 1).
// Goal: create a |-⟩ state on this qubit (|-⟩ = (|0⟩ - |1⟩) / sqrt(2)).
operation MinusState (qs : Qubit[]) : ()
{
body
{
// In this task, as well as in all subsequent ones, you have to come up with the solution yourself.
operation MinusState (qs : Qubit[]) : Unit {
// In this task, as well as in all subsequent ones, you have to come up with the solution yourself.
// ...
}
// ...
}
// Task 3*. Unequal superposition
// Inputs:
// 1) a qubit in |0⟩ state (stored in an array of length 1).
// 2) angle alpha, in radians, represented as Double
// Goal: create a cos(alpha) * |0⟩ + sin(alpha) * |1⟩ state on this qubit.
operation UnequalSuperposition (qs : Qubit[], alpha : Double) : ()
{
body
{
// Hint: Experiment with rotation gates from Microsoft.Quantum.Primitive namespace.
// Note that all rotation operators rotate the state by _half_ of its angle argument.
operation UnequalSuperposition (qs : Qubit[], alpha : Double) : Unit {
// Hint: Experiment with rotation gates from Microsoft.Quantum.Primitive namespace.
// Note that all rotation operators rotate the state by _half_ of its angle argument.
// ...
}
// ...
}
// Task 4. Superposition of all basis vectors on two qubits
// Input: two qubits in |00⟩ state (stored in an array of length 2).
// Goal: create the following state on these qubits: (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2.
operation AllBasisVectors_TwoQubits (qs : Qubit[]) : ()
{
body
{
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
operation AllBasisVectors_TwoQubits (qs : Qubit[]) : Unit {
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
// ...
}
// ...
}
// Task 5. Superposition of basis vectors with phases
// Input: two qubits in |00⟩ state (stored in an array of length 2).
// Goal: create the following state on these qubits: (|00⟩ + i*|01⟩ - |10⟩ - i*|11⟩) / 2.
operation AllBasisVectorsWithPhases_TwoQubits (qs : Qubit[]) : ()
{
body
{
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
operation AllBasisVectorsWithPhases_TwoQubits (qs : Qubit[]) : Unit {
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
// Hint: Is this state separable?
// ...
}
// Hint: Is this state separable?
// ...
}
// Task 6. Bell state
// Input: two qubits in |00⟩ state (stored in an array of length 2).
// Goal: create a Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2) on these qubits.
operation BellState (qs : Qubit[]) : ()
{
body
{
// ...
}
operation BellState (qs : Qubit[]) : Unit {
// ...
}
// Task 7. All Bell states
// Inputs:
// 1) two qubits in |00⟩ state (stored in an array of length 2)
@ -122,39 +105,30 @@ namespace Quantum.Kata.Superposition
// 1: |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
// 2: |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
// 3: |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
operation AllBellStates (qs : Qubit[], index : Int) : ()
{
body
{
// ...
}
operation AllBellStates (qs : Qubit[], index : Int) : Unit {
// ...
}
// Task 8. Greenberger–Horne–Zeilinger state
// Input: N qubits in |0...0⟩ state.
// Goal: create a GHZ state (|0...0⟩ + |1...1⟩) / sqrt(2) on these qubits.
operation GHZ_State (qs : Qubit[]) : ()
{
body
{
// Hint: N can be found as Length(qs).
operation GHZ_State (qs : Qubit[]) : Unit {
// Hint: N can be found as Length(qs).
// ...
}
// ...
}
// Task 9. Superposition of all basis vectors
// Input: N qubits in |0...0⟩ state.
// Goal: create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩
// (i.e. state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N) ).
operation AllBasisVectorsSuperposition (qs : Qubit[]) : ()
{
body
{
// ...
}
operation AllBasisVectorsSuperposition (qs : Qubit[]) : Unit {
// ...
}
// Task 10. Superposition of |0...0⟩ and given bit string
// Inputs:
// 1) N qubits in |0...0⟩ state
@ -163,63 +137,51 @@ namespace Quantum.Kata.Superposition
// Bit values false and true correspond to |0⟩ and |1⟩ states.
// You are guaranteed that the qubit array and the bit string have the same length.
// You are guaranteed that the first bit of the bit string is true.
// Example: for bit string = [true; false] the qubit state required is (|00⟩ + |10⟩) / sqrt(2).
operation ZeroAndBitstringSuperposition (qs : Qubit[], bits : Bool[]) : ()
{
body
{
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(bits), Length(qs), "Arrays should have the same length");
AssertBoolEqual(bits[0], true, "First bit of the input bit string should be set to true");
// Example: for bit string = [true, false] the qubit state required is (|00⟩ + |10⟩) / sqrt(2).
operation ZeroAndBitstringSuperposition (qs : Qubit[], bits : Bool[]) : Unit {
// The following lines enforce the constraints on the input that you are given.
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
AssertIntEqual(Length(bits), Length(qs), "Arrays should have the same length");
AssertBoolEqual(bits[0], true, "First bit of the input bit string should be set to true");
// ...
}
// ...
}
// Task 11. Superposition of two bit strings
// Inputs:
// 1) N qubits in |0...0⟩ state
// 2) two bit string represented as Bool[]s
// Goal: create an equal superposition of two basis states given by the bit strings.
// Bit values false and true correspond to |0⟩ and |1⟩ states.
// Example: for bit strings [false; true; false] and [false; false; true]
// Example: for bit strings [false, true, false] and [false, false, true]
// the qubit state required is (|010⟩ + |001⟩) / sqrt(2).
// You are guaranteed that the both bit strings have the same length as the qubit array,
// and that the bit strings will differ in at least one bit.
operation TwoBitstringSuperposition (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : ()
{
body
{
// ...
}
operation TwoBitstringSuperposition (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Unit {
// ...
}
// Task 12**. W state on 2^k qubits
// Input: N = 2^k qubits in |0...0⟩ state.
// Goal: create a W state (https://en.wikipedia.org/wiki/W_state) on these qubits.
// W state is an equal superposition of all basis states on N qubits of Hamming weight 1.
// Example: for N = 4, W state is (|1000⟩ + |0100⟩ + |0010⟩ + |0001⟩) / 2.
operation WState_PowerOfTwo (qs : Qubit[]) : ()
{
body
{
// Hint: you can use Controlled functor to perform arbitrary controlled gates.
operation WState_PowerOfTwo (qs : Qubit[]) : Unit {
// Hint: you can use Controlled modifier to perform arbitrary controlled gates.
// ...
}
}
// Task 13**. W state on arbitrary number of qubits
// Input: N qubits in |0...0⟩ state (N is not necessarily a power of 2).
// Goal: create a W state (https://en.wikipedia.org/wiki/W_state) on these qubits.
// W state is an equal superposition of all basis states on N qubits of Hamming weight 1.
// Example: for N = 3, W state is (|100⟩ + |010⟩ + |001⟩) / sqrt(3).
operation WState_Arbitrary (qs : Qubit[]) : ()
{
body
{
operation WState_Arbitrary (qs : Qubit[]) : Unit {
// ...
}
}
}

Просмотреть файл

@ -1,260 +1,213 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.Superposition
{
namespace Quantum.Kata.Superposition {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
open Microsoft.Quantum.Extensions.Testing;
// ------------------------------------------------------
operation AssertEqualOnZeroState (N : Int, testImpl : (Qubit[] => ()), refImpl : (Qubit[] => () : Adjoint)) : ()
{
body
{
using (qs = Qubit[N])
{
// apply operation that needs to be tested
testImpl(qs);
// apply adjoint reference operation and check that the result is |0⟩
(Adjoint refImpl)(qs);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
operation AssertEqualOnZeroState (N : Int, testImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
using (qs = Qubit[N]) {
// apply operation that needs to be tested
testImpl(qs);
// apply adjoint reference operation and check that the result is |0⟩
Adjoint refImpl(qs);
// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
// ------------------------------------------------------
operation T01_PlusState_Test () : ()
{
body
{
AssertEqualOnZeroState(1, PlusState, PlusState_Reference);
operation T01_PlusState_Test () : Unit {
AssertEqualOnZeroState(1, PlusState, PlusState_Reference);
}
// ------------------------------------------------------
operation T02_MinusState_Test () : Unit {
AssertEqualOnZeroState(1, MinusState, MinusState_Reference);
}
// ------------------------------------------------------
operation T03_UnequalSuperposition_Test () : Unit {
// cross-test
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.0), ApplyToEachA(I, _));
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.5 * PI()), ApplyToEachA(X, _));
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.5 * PI()), ApplyToEachA(Y, _));
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.25 * PI()), PlusState_Reference);
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.75 * PI()), MinusState_Reference);
for (i in 1 .. 36) {
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
AssertEqualOnZeroState(1, UnequalSuperposition(_, alpha), UnequalSuperposition_Reference(_, alpha));
}
}
// ------------------------------------------------------
operation T02_MinusState_Test () : ()
{
body
{
AssertEqualOnZeroState(1, MinusState, MinusState_Reference);
operation T04_AllBasisVectors_TwoQubits_Test () : Unit {
// We only check for 2 qubits.
AssertEqualOnZeroState(2, AllBasisVectors_TwoQubits, AllBasisVectors_TwoQubits_Reference);
}
// ------------------------------------------------------
operation T05_AllBasisVectorsWithPhases_TwoQubits_Test () : Unit {
// We only check for 2 qubits.
AssertEqualOnZeroState(2, AllBasisVectorsWithPhases_TwoQubits, AllBasisVectorsWithPhases_TwoQubits_Reference);
}
// ------------------------------------------------------
operation T06_BellState_Test () : Unit {
AssertEqualOnZeroState(2, BellState, BellState_Reference);
}
// ------------------------------------------------------
operation T07_AllBellStates_Test () : Unit {
for (i in 0 .. 3) {
AssertEqualOnZeroState(2, AllBellStates(_, i), AllBellStates_Reference(_, i));
}
}
// ------------------------------------------------------
operation T03_UnequalSuperposition_Test () : ()
{
body
{
// cross-test
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.0), ApplyToEachA(I, _));
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.5 * PI()), ApplyToEachA(X, _));
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.5 * PI()), ApplyToEachA(Y, _));
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.25 * PI()), PlusState_Reference);
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.75 * PI()), MinusState_Reference);
for (i in 1..36) {
let alpha = 2.0 * PI() * ToDouble(i) / 36.0;
AssertEqualOnZeroState(1, UnequalSuperposition(_, alpha), UnequalSuperposition_Reference(_, alpha));
}
operation T08_GHZ_State_Test () : Unit {
// for N = 1 it's just |+⟩
AssertEqualOnZeroState(1, GHZ_State, PlusState_Reference);
// for N = 2 it's Bell state
AssertEqualOnZeroState(2, GHZ_State, BellState_Reference);
for (n in 3 .. 9) {
AssertEqualOnZeroState(n, GHZ_State, GHZ_State_Reference);
}
}
// ------------------------------------------------------
operation T04_AllBasisVectors_TwoQubits_Test () : ()
{
body
{
// We only check for 2 qubits.
AssertEqualOnZeroState(2, AllBasisVectors_TwoQubits, AllBasisVectors_TwoQubits_Reference);
operation T09_AllBasisVectorsSuperposition_Test () : Unit {
// for N = 1 it's just |+⟩
AssertEqualOnZeroState(1, AllBasisVectorsSuperposition, PlusState_Reference);
for (n in 2 .. 9) {
AssertEqualOnZeroState(n, AllBasisVectorsSuperposition, AllBasisVectorsSuperposition_Reference);
}
}
// ------------------------------------------------------
operation T05_AllBasisVectorsWithPhases_TwoQubits_Test () : ()
{
body
{
// We only check for 2 qubits.
AssertEqualOnZeroState(2, AllBasisVectorsWithPhases_TwoQubits, AllBasisVectorsWithPhases_TwoQubits_Reference);
operation T10_ZeroAndBitstringSuperposition_Test () : Unit {
// compare with results of previous operations
AssertEqualOnZeroState(1, ZeroAndBitstringSuperposition(_, [true]), PlusState_Reference);
AssertEqualOnZeroState(2, ZeroAndBitstringSuperposition(_, [true, true]), BellState_Reference);
AssertEqualOnZeroState(3, ZeroAndBitstringSuperposition(_, [true, true, true]), GHZ_State_Reference);
if (true) {
let b = [true, false];
AssertEqualOnZeroState(2, ZeroAndBitstringSuperposition(_, b), ZeroAndBitstringSuperposition_Reference(_, b));
}
if (true) {
let b = [true, false, true];
AssertEqualOnZeroState(3, ZeroAndBitstringSuperposition(_, b), ZeroAndBitstringSuperposition_Reference(_, b));
}
if (true) {
let b = [true, false, true, true, false, false];
AssertEqualOnZeroState(6, ZeroAndBitstringSuperposition(_, b), ZeroAndBitstringSuperposition_Reference(_, b));
}
}
// ------------------------------------------------------
operation T06_BellState_Test () : ()
{
body
{
AssertEqualOnZeroState(2, BellState, BellState_Reference);
operation T11_TwoBitstringSuperposition_Test () : Unit {
// compare with results of previous operations
AssertEqualOnZeroState(1, TwoBitstringSuperposition(_, [true], [false]), PlusState_Reference);
AssertEqualOnZeroState(2, TwoBitstringSuperposition(_, [false, false], [true, true]), BellState_Reference);
AssertEqualOnZeroState(3, TwoBitstringSuperposition(_, [true, true, true], [false, false, false]), GHZ_State_Reference);
// compare with reference implementation
// diff in first position
for (i in 1 .. 1) {
let b1 = [false, true];
let b2 = [true, false];
AssertEqualOnZeroState(2, TwoBitstringSuperposition(_, b1, b2), TwoBitstringSuperposition_Reference(_, b1, b2));
}
for (i in 1 .. 1) {
let b1 = [true, true, false];
let b2 = [false, true, true];
AssertEqualOnZeroState(3, TwoBitstringSuperposition(_, b1, b2), TwoBitstringSuperposition_Reference(_, b1, b2));
}
// diff in last position
for (i in 1 .. 1) {
let b1 = [false, true, true, false];
let b2 = [false, true, true, true];
AssertEqualOnZeroState(4, TwoBitstringSuperposition(_, b1, b2), TwoBitstringSuperposition_Reference(_, b1, b2));
}
// diff in the middle
for (i in 1 .. 1) {
let b1 = [true, false, false, false];
let b2 = [true, false, true, true];
AssertEqualOnZeroState(4, TwoBitstringSuperposition(_, b1, b2), TwoBitstringSuperposition_Reference(_, b1, b2));
}
}
// ------------------------------------------------------
operation T07_AllBellStates_Test () : ()
{
body
{
for (i in 0..3) {
AssertEqualOnZeroState(2, AllBellStates(_, i), AllBellStates_Reference(_, i));
}
operation T12_WState_PowerOfTwo_Test () : Unit {
// separate check for N = 1 (return must be |1⟩)
using (qs = Qubit[1]) {
WState_PowerOfTwo(qs);
Assert([PauliZ], qs, One, "");
X(qs[0]);
}
AssertEqualOnZeroState(2, WState_PowerOfTwo, TwoBitstringSuperposition_Reference(_, [false, true], [true, false]));
AssertEqualOnZeroState(4, WState_PowerOfTwo, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(8, WState_PowerOfTwo, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(16, WState_PowerOfTwo, WState_PowerOfTwo_Reference);
}
// ------------------------------------------------------
operation T13_WState_Arbitrary_Test () : Unit {
// separate check for N = 1 (return must be |1⟩)
using (qs = Qubit[1]) {
WState_Arbitrary_Reference(qs);
Assert([PauliZ], qs, One, "");
X(qs[0]);
}
// cross-tests
AssertEqualOnZeroState(2, WState_Arbitrary, TwoBitstringSuperposition_Reference(_, [false, true], [true, false]));
AssertEqualOnZeroState(2, WState_Arbitrary, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(4, WState_Arbitrary, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(8, WState_Arbitrary, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(16, WState_Arbitrary, WState_PowerOfTwo_Reference);
for (i in 2 .. 16) {
AssertEqualOnZeroState(i, WState_Arbitrary, WState_Arbitrary_Reference);
}
}
// ------------------------------------------------------
operation T08_GHZ_State_Test () : ()
{
body
{
// for N = 1 it's just |+⟩
AssertEqualOnZeroState(1, GHZ_State, PlusState_Reference);
// for N = 2 it's Bell state
AssertEqualOnZeroState(2, GHZ_State, BellState_Reference);
for (n in 3..9) {
AssertEqualOnZeroState(n, GHZ_State, GHZ_State_Reference);
}
}
}
// ------------------------------------------------------
operation T09_AllBasisVectorsSuperposition_Test () : ()
{
body
{
// for N = 1 it's just |+⟩
AssertEqualOnZeroState(1, AllBasisVectorsSuperposition, PlusState_Reference);
for (n in 2..9) {
AssertEqualOnZeroState(n, AllBasisVectorsSuperposition, AllBasisVectorsSuperposition_Reference);
}
}
}
// ------------------------------------------------------
operation T10_ZeroAndBitstringSuperposition_Test () : ()
{
body
{
// compare with results of previous operations
AssertEqualOnZeroState(1, ZeroAndBitstringSuperposition(_, [true]), PlusState_Reference);
AssertEqualOnZeroState(2, ZeroAndBitstringSuperposition(_, [true; true]), BellState_Reference);
AssertEqualOnZeroState(3, ZeroAndBitstringSuperposition(_, [true; true; true]), GHZ_State_Reference);
if (true) {
let b = [true; false];
AssertEqualOnZeroState(2, ZeroAndBitstringSuperposition(_, b),
ZeroAndBitstringSuperposition_Reference(_, b));
}
if (true) {
let b = [true; false; true];
AssertEqualOnZeroState(3, ZeroAndBitstringSuperposition(_, b),
ZeroAndBitstringSuperposition_Reference(_, b));
}
if (true) {
let b = [true; false; true; true; false; false];
AssertEqualOnZeroState(6, ZeroAndBitstringSuperposition(_, b),
ZeroAndBitstringSuperposition_Reference(_, b));
}
}
}
// ------------------------------------------------------
operation T11_TwoBitstringSuperposition_Test () : ()
{
body
{
// compare with results of previous operations
AssertEqualOnZeroState(1, TwoBitstringSuperposition(_, [true], [false]), PlusState_Reference);
AssertEqualOnZeroState(2, TwoBitstringSuperposition(_, [false; false], [true; true]), BellState_Reference);
AssertEqualOnZeroState(3, TwoBitstringSuperposition(_, [true; true; true], [false; false; false]), GHZ_State_Reference);
// compare with reference implementation
// diff in first position
for (i in 1..1)
{
let b1 = [false; true];
let b2 = [true; false];
AssertEqualOnZeroState(2, TwoBitstringSuperposition(_, b1, b2),
TwoBitstringSuperposition_Reference(_, b1, b2));
}
for (i in 1..1)
{
let b1 = [true; true; false];
let b2 = [false; true; true];
AssertEqualOnZeroState(3, TwoBitstringSuperposition(_, b1, b2),
TwoBitstringSuperposition_Reference(_, b1, b2));
}
// diff in last position
for (i in 1..1)
{
let b1 = [false; true; true; false];
let b2 = [false; true; true; true];
AssertEqualOnZeroState(4, TwoBitstringSuperposition(_, b1, b2),
TwoBitstringSuperposition_Reference(_, b1, b2));
}
// diff in the middle
for (i in 1..1)
{
let b1 = [true; false; false; false];
let b2 = [true; false; true; true];
AssertEqualOnZeroState(4, TwoBitstringSuperposition(_, b1, b2),
TwoBitstringSuperposition_Reference(_, b1, b2));
}
}
}
// ------------------------------------------------------
operation T12_WState_PowerOfTwo_Test () : ()
{
body
{
// separate check for N = 1 (return must be |1⟩)
using (qs = Qubit[1]) {
WState_PowerOfTwo(qs);
Assert([PauliZ], qs, One, "");
X(qs[0]);
}
AssertEqualOnZeroState(2, WState_PowerOfTwo, TwoBitstringSuperposition_Reference(_, [false; true], [true; false]));
AssertEqualOnZeroState(4, WState_PowerOfTwo, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(8, WState_PowerOfTwo, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(16, WState_PowerOfTwo, WState_PowerOfTwo_Reference);
}
}
// ------------------------------------------------------
operation T13_WState_Arbitrary_Test () : ()
{
body
{
// separate check for N = 1 (return must be |1⟩)
using (qs = Qubit[1]) {
WState_Arbitrary_Reference(qs);
Assert([PauliZ], qs, One, "");
X(qs[0]);
}
// cross-tests
AssertEqualOnZeroState(2, WState_Arbitrary, TwoBitstringSuperposition_Reference(_, [false; true], [true; false]));
AssertEqualOnZeroState(2, WState_Arbitrary, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(4, WState_Arbitrary, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(8, WState_Arbitrary, WState_PowerOfTwo_Reference);
AssertEqualOnZeroState(16, WState_Arbitrary, WState_PowerOfTwo_Reference);
for (i in 2..16) {
AssertEqualOnZeroState(i, WState_Arbitrary, WState_Arbitrary_Reference);
}
}
}
}
}

Просмотреть файл

@ -1,160 +1,165 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs file.
// but feel free to look up the solution if you get stuck.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.Teleportation
{
namespace Quantum.Kata.Teleportation {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
//////////////////////////////////////////////////////////////////
// Part I. Standard teleportation
//////////////////////////////////////////////////////////////////
// Task 1.1. Entangled pair
operation Entangle_Reference (qAlice : Qubit, qBob : Qubit) : ()
{
body {
operation Entangle_Reference (qAlice : Qubit, qBob : Qubit) : Unit {
body (...) {
H(qAlice);
CNOT(qAlice, qBob);
}
adjoint auto;
adjoint invert;
}
// Task 1.2. Send the message (Alice's task)
operation SendMessage_Reference (qAlice : Qubit, qMessage : Qubit) : (Bool, Bool)
{
body {
CNOT(qMessage, qAlice);
H(qMessage);
return (M(qMessage) == One, M(qAlice) == One);
}
operation SendMessage_Reference (qAlice : Qubit, qMessage : Qubit) : (Bool, Bool) {
CNOT(qMessage, qAlice);
H(qMessage);
return (M(qMessage) == One, M(qAlice) == One);
}
// Task 1.3. Reconstruct the message (Bob's task)
operation ReconstructMessage_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
if (b1) { Z(qBob); }
if (b2) { X(qBob); }
operation ReconstructMessage_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
if (b1) {
Z(qBob);
}
}
// Task 1.4. Standard teleportation protocol
operation StandardTeleport_Reference (qAlice : Qubit, qBob : Qubit, qMessage : Qubit):()
{
body{
Entangle_Reference(qAlice, qBob);
let classicalBits = SendMessage_Reference(qAlice, qMessage);
// Alice sends the classical bits to Bob.
// Bob uses these bits to transform his part of the entangled pair into |ψ⟩.
ReconstructMessage_Reference(qBob, classicalBits);
}
}
// Task 1.5. Prepare the message specified and send it (Alice's task)
operation PrepareAndSendMessage_Reference (qAlice : Qubit, basis : Pauli, state : Bool) : (Bool, Bool)
{
body {
mutable classicalBits = (false, false);
using (qs = Qubit[1])
{
if (state) { X(qs[0]); }
PrepareQubit(basis, qs[0]);
set classicalBits = SendMessage_Reference(qAlice, qs[0]);
Reset(qs[0]);
}
return classicalBits;
if (b2) {
X(qBob);
}
}
// Task 1.6. Reconstruct the message and measure it (Bob's task)
operation ReconstructAndMeasureMessage_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool), basis : Pauli) : (Bool)
{
body {
ReconstructMessage_Reference(qBob, (b1, b2));
return (Measure([basis], [qBob]) == One);
}
// Task 1.4. Standard teleportation protocol
operation StandardTeleport_Reference (qAlice : Qubit, qBob : Qubit, qMessage : Qubit) : Unit {
Entangle_Reference(qAlice, qBob);
let classicalBits = SendMessage_Reference(qAlice, qMessage);
// Alice sends the classical bits to Bob.
// Bob uses these bits to transform his part of the entangled pair into |ψ⟩.
ReconstructMessage_Reference(qBob, classicalBits);
}
// Task 1.5. Prepare the message specified and send it (Alice's task)
operation PrepareAndSendMessage_Reference (qAlice : Qubit, basis : Pauli, state : Bool) : (Bool, Bool) {
mutable classicalBits = (false, false);
using (qs = Qubit[1]) {
if (state) {
X(qs[0]);
}
PrepareQubit(basis, qs[0]);
set classicalBits = SendMessage_Reference(qAlice, qs[0]);
Reset(qs[0]);
}
return classicalBits;
}
// Task 1.6. Reconstruct the message and measure it (Bob's task)
operation ReconstructAndMeasureMessage_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool), basis : Pauli) : Bool {
ReconstructMessage_Reference(qBob, (b1, b2));
return Measure([basis], [qBob]) == One;
}
//////////////////////////////////////////////////////////////////
// Part II. Teleportation using different entangled pair
//////////////////////////////////////////////////////////////////
// Task 2.1. Reconstruct the message if the entangled qubits were in the state |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2).
operation ReconstructMessage_PhiMinus_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
// Bob can apply a Z gate to his qubit to convert the pair to |Φ⁺⟩
// and use the standard teleportation reconstruction process.
if (!b1) { Z(qBob); }
if (b2) { X(qBob); }
operation ReconstructMessage_PhiMinus_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
// Bob can apply a Z gate to his qubit to convert the pair to |Φ⁺⟩
// and use the standard teleportation reconstruction process.
if (not b1) {
Z(qBob);
}
if (b2) {
X(qBob);
}
}
// Task 2.2. Reconstruct the message if the entangled qubits were in the state |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2).
operation ReconstructMessage_PsiPlus_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
// Bob can apply an X gate to his qubit to convert the pair to |Φ⁺⟩
// and use the standard teleportation reconstruction process.
if (b1) { Z(qBob); }
if (!b2) { X(qBob); }
operation ReconstructMessage_PsiPlus_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
// Bob can apply an X gate to his qubit to convert the pair to |Φ⁺⟩
// and use the standard teleportation reconstruction process.
if (b1) {
Z(qBob);
}
if (not b2) {
X(qBob);
}
}
// Task 2.3. Reconstruct the message if the entangled qubits were in the state |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2).
operation ReconstructMessage_PsiMinus_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
// Bob can apply a Z gate and an X gate to his qubit to convert the pair to |Φ⁺⟩
// and use the standard teleportation reconstruction process.
if (!b1) { Z(qBob); }
if (!b2) { X(qBob); }
operation ReconstructMessage_PsiMinus_Reference (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
// Bob can apply a Z gate and an X gate to his qubit to convert the pair to |Φ⁺⟩
// and use the standard teleportation reconstruction process.
if (not b1) {
Z(qBob);
}
if (not b2) {
X(qBob);
}
}
//////////////////////////////////////////////////////////////////
// Part III. Principle of deferred measurement
//////////////////////////////////////////////////////////////////
// Task 3.1. Measurement-free teleportation.
operation MeasurementFreeTeleport_Reference (qAlice : Qubit, qBob : Qubit, qMessage : Qubit) : ()
{
body {
// The first part of the circuit is similar to Alice's part, but without measurements.
CNOT(qMessage, qAlice);
H(qMessage);
// Classically controlled gates applied by Bob are replaced by controlled gates
(Controlled Z)([qMessage], qBob);
(Controlled X)([qAlice], qBob);
}
operation MeasurementFreeTeleport_Reference (qAlice : Qubit, qBob : Qubit, qMessage : Qubit) : Unit {
// The first part of the circuit is similar to Alice's part, but without measurements.
CNOT(qMessage, qAlice);
H(qMessage);
// Classically controlled gates applied by Bob are replaced by controlled gates
Controlled Z([qMessage], qBob);
Controlled X([qAlice], qBob);
}
//////////////////////////////////////////////////////////////////
// Part IV. Teleportation with three entangled qubits
//////////////////////////////////////////////////////////////////
// Task 4.1. Entangled trio
operation EntangleThreeQubits_Reference (qAlice : Qubit, qBob : Qubit, qCharlie : Qubit) : ()
{
body
{
operation EntangleThreeQubits_Reference (qAlice : Qubit, qBob : Qubit, qCharlie : Qubit) : Unit {
body (...) {
H(qAlice);
H(qBob);
X(qCharlie);
CCNOT(qAlice, qBob, qCharlie);
X(qAlice);
X(qBob);
@ -163,16 +168,25 @@ namespace Quantum.Kata.Teleportation
X(qAlice);
X(qBob);
}
adjoint auto;
adjoint invert;
}
// Task 4.2. Reconstruct the message (Charlie's task)
operation ReconstructMessageWhenThreeEntangledQubits_Reference (qCharlie : Qubit, (b1 : Bool, b2 : Bool), b3 : Bool) : ()
{
body {
if (b1) { Z(qCharlie); }
if (b2) { Z(qCharlie); Y(qCharlie); }
if (b3) { X(qCharlie); }
operation ReconstructMessageWhenThreeEntangledQubits_Reference (qCharlie : Qubit, (b1 : Bool, b2 : Bool), b3 : Bool) : Unit {
if (b1) {
Z(qCharlie);
}
if (b2) {
Z(qCharlie);
Y(qCharlie);
}
if (b3) {
X(qCharlie);
}
}
}

Просмотреть файл

@ -1,58 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.Teleportation
{
namespace Quantum.Kata.Teleportation {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Convert;
open Microsoft.Quantum.Extensions.Math;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Teleportation" quantum kata is a series of exercises designed
// "Teleportation" quantum kata is a series of exercises designed
// to get you familiar with programming in Q#.
// It covers the quantum teleportation protocol which allows you
// to communicate a quantum state using only classical communication
// to communicate a quantum state using only classical communication
// and previously shared quantum entanglement.
//
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
//////////////////////////////////////////////////////////////////
// Part I. Standard Teleportation
//////////////////////////////////////////////////////////////////
// We split the teleportation protocol into several steps, following the description at
// https://docs.microsoft.com/en-us/quantum/quantum-techniques-6-puttingitalltogether :
// * Preparation (creating the entangled pair of qubits that are sent to Alice and Bob).
// * Sending the message (Alice's task): Entangling the message qubit with Alice's qubit
// and extracting two classical bits to be sent to Bob.
// * Reconstructing the message (Bob's task): Using the two classical bits Bob received from Alice
// * Reconstructing the message (Bob's task): Using the two classical bits Bob received from Alice
// to get Bob's qubit into the state in which the message qubit had been originally.
// Finally, we compose these steps into the complete teleportation protocol.
// Task 1.1. Entangled pair
// Input: two qubits qAlice and qBob, each in |0⟩ state.
// Goal: create a Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2) on these qubits.
//
// In the context of the quantum teleportation protocol, this is the preparation step:
// qubits qAlice and qBob will be sent to Alice and Bob, respectively.
operation Entangle (qAlice : Qubit, qBob : Qubit) : ()
{
body {
// ...
}
// qubits qAlice and qBob will be sent to Alice and Bob, respectively.
operation Entangle (qAlice : Qubit, qBob : Qubit) : Unit {
// ...
}
// Task 1.2. Send the message (Alice's task)
// Entangle the message qubit with Alice's qubit
// and extract two classical bits to be sent to Bob.
// Inputs:
// Inputs:
// 1) Alice's part of the entangled pair of qubits qAlice.
// 2) The message qubit qMessage.
// Output:
@ -61,53 +60,47 @@ namespace Quantum.Kata.Teleportation
// the second bit - the result of measurement of Alice's qubit.
// Represent measurement result 'One' as 'True' and 'Zero' as 'False'.
// The state of the qubits in the end of the operation doesn't matter.
operation SendMessage (qAlice : Qubit, qMessage : Qubit) : (Bool, Bool)
{
body {
// ...
return (false, false);
}
operation SendMessage (qAlice : Qubit, qMessage : Qubit) : (Bool, Bool) {
// ...
return (false, false);
}
// Task 1.3. Reconstruct the message (Bob's task)
// Transform Bob's qubit into the required state using the two classical bits
// received from Alice.
// Inputs:
// 1) Bob's part of the entangled pair of qubits qBob.
// 2) The tuple of classical bits received from Alice,
// 2) The tuple of classical bits received from Alice,
// in the format used in task 1.2.
// Goal: transform Bob's qubit qBob into the state in which the message qubit had been originally.
operation ReconstructMessage (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
// ...
}
operation ReconstructMessage (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
// ...
}
// Task 1.4. Standard teleportation protocol
// Put together the steps implemented in tasks 1.1 - 1.3 to implement
// Put together the steps implemented in tasks 1.1 - 1.3 to implement
// the full teleportation protocol.
// Inputs:
// 1) The two qubits qAlice and qBob in |0⟩ state.
// Inputs:
// 1) The two qubits qAlice and qBob in |0⟩ state.
// 2) The message qubit qMessage in the state |ψ⟩ to be teleported.
// Goal: transform Bob's qubit qBob into the state |ψ⟩.
// The state of the qubits qAlice and qMessage in the end of the operation doesn't matter.
operation StandardTeleport (qAlice : Qubit, qBob : Qubit, qMessage : Qubit) : ()
{
body {
// ...
}
operation StandardTeleport (qAlice : Qubit, qBob : Qubit, qMessage : Qubit) : Unit {
// ...
}
// Task 1.5. Prepare a state and send it as a message (Alice's task)
// Given a Pauli basis along with a state 'True' as 'One' or 'False'
// as 'Zero' prepare a message qubit, entangle it with Alice's qubit,
// Given a Pauli basis along with a state 'True' as 'One' or 'False'
// as 'Zero' prepare a message qubit, entangle it with Alice's qubit,
// and extract two classical bits to be sent to Bob.
// Inputs:
// Inputs:
// 1) Alice's part of the entangled pair of qubits qAlice.
// 2) A PauliX, PauliY, or PauliZ basis in which the message
// 2) A PauliX, PauliY, or PauliZ basis in which the message
// qubit should be prepared
// 3) A Bool indicating the eigenstate in which the message
// 3) A Bool indicating the eigenstate in which the message
// qubit should be prepared
// Output:
// Two classical bits Alice will send to Bob via classical channel as a tuple of Bool values.
@ -115,158 +108,141 @@ namespace Quantum.Kata.Teleportation
// the second bit - the result of measurement of Alice's qubit.
// Represent measurement result 'One' as 'True' and 'Zero' as 'False'.
// The state of the qubit qAlice in the end of the operation doesn't matter.
operation PrepareAndSendMessage (qAlice : Qubit, basis : Pauli, state : Bool) : (Bool, Bool)
{
body {
// ...
return (false, false);
}
operation PrepareAndSendMessage (qAlice : Qubit, basis : Pauli, state : Bool) : (Bool, Bool) {
// ...
return (false, false);
}
// Task 1.6. Reconstruct and measure the message state (Bob's task)
// Transform Bob's qubit into the required state using the two classical bits
// received from Alice and measure it in the same basis in which she prepared the message.
// Inputs:
// 1) Bob's part of the entangled pair of qubits qBob.
// 2) The tuple of classical bits received from Alice,
// 2) The tuple of classical bits received from Alice,
// in the format used in task 1.5.
// 3) The PauliX, PauliY, or PauliZ basis in which the
// 3) The PauliX, PauliY, or PauliZ basis in which the
// message qubit was originally prepared
// Output:
// A Bool indicating the eigenstate in which the message qubit was prepared, 'One' as
// A Bool indicating the eigenstate in which the message qubit was prepared, 'One' as
// 'True' and 'Zero' as 'False'.
// Goal: transform Bob's qubit qBob into the state in which the message qubit was originally
// Goal: transform Bob's qubit qBob into the state in which the message qubit was originally
// prepared, then measure it. The state of the qubit qBob in the end of the operation doesn't matter.
operation ReconstructAndMeasureMessage (qBob : Qubit, (b1 : Bool, b2 : Bool), basis : Pauli) : (Bool)
{
body {
// ...
return false;
}
operation ReconstructAndMeasureMessage (qBob : Qubit, (b1 : Bool, b2 : Bool), basis : Pauli) : Bool {
// ...
return false;
}
// Task 1.7. Testing standard quantum teleportation
// Goal: Test that the StandardTeleport operation from task 1.4 is able
// Goal: Test that the StandardTeleport operation from task 1.4 is able
// to successfully teleport the states |0⟩ and |1⟩, as well as superpositions such as
// (|0⟩ + |1⟩) / sqrt(2),
// (|0⟩ - |1⟩) / sqrt(2),
// (|0⟩ + i|1⟩) / sqrt(2), and
// (|0⟩ + i|1⟩) / sqrt(2), and
// (|0⟩ - i|1⟩) / sqrt(2)
operation StandardTeleport_Test () : ()
{
body {
// Hint: You may find your answers for 1.5 and 1.6 useful
operation StandardTeleport_Test () : Unit {
// Hint: You may find your answers for 1.5 and 1.6 useful
// StandardTeleport_Test appears in the list of unit tests for the solution; run it to verify your code.
// StandardTeleport_Test appears in the list of unit tests for the solution; run it to verify your code.
// ...
}
// ...
}
//////////////////////////////////////////////////////////////////
// Part II. Teleportation using different entangled pair
//////////////////////////////////////////////////////////////////
// In this section we will take a look at the changes in the reconstruction process (Bob's task)
// if the qubits shared between Alice and Bob are entangled in a different state.
// Alice's part of the protocol remains the same in all tasks.
// As a reminder, the standard teleportation protocol requires shared qubits in state
// As a reminder, the standard teleportation protocol requires shared qubits in state
// |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
// In each task, the inputs are
// In each task, the inputs are
// 1) Bob's part of the entangled pair of qubits qBob.
// 2) the tuple of classical bits received from Alice,
// 2) the tuple of classical bits received from Alice,
// in the format used in task 1.2.
// The goal is to transform Bob's qubit qBob into the state in which the message qubit had been originally.
// Task 2.1. Reconstruct the message if the entangled qubits were in the state |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2).
operation ReconstructMessage_PhiMinus (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
// ...
}
operation ReconstructMessage_PhiMinus (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
// ...
}
// Task 2.2. Reconstruct the message if the entangled qubits were in the state |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2).
operation ReconstructMessage_PsiPlus (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
// ...
}
operation ReconstructMessage_PsiPlus (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
// ...
}
// Task 2.3. Reconstruct the message if the entangled qubits were in the state |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2).
operation ReconstructMessage_PsiMinus (qBob : Qubit, (b1 : Bool, b2 : Bool)) : ()
{
body {
// ...
}
operation ReconstructMessage_PsiMinus (qBob : Qubit, (b1 : Bool, b2 : Bool)) : Unit {
// ...
}
//////////////////////////////////////////////////////////////////
// Part III. Principle of deferred measurement
//////////////////////////////////////////////////////////////////
// The principle of deferred measurement claims that measurements can be moved
// from an intermediate stage of a quantum circuit to the end of the circuit.
// If the measurement results are used to perform classically controlled operations,
// they can be replaced by controlled quantum operations.
// In this task we will apply this principle to the teleportation circuit.
// Task 3.1. Measurement-free teleportation.
// Inputs:
// 1) The two qubits qAlice and qBob in |Φ⁺⟩ state.
// Inputs:
// 1) The two qubits qAlice and qBob in |Φ⁺⟩ state.
// 2) The message qubit qMessage in the state |ψ⟩ to be teleported.
// Goal: transform Bob's qubit qBob into the state |ψ⟩ using no measurements.
// At the end of the operation qubits qAlice and qMessage should not be entangled with qBob.
operation MeasurementFreeTeleport (qAlice : Qubit, qBob : Qubit, qMessage : Qubit) : ()
{
body {
// ...
}
operation MeasurementFreeTeleport (qAlice : Qubit, qBob : Qubit, qMessage : Qubit) : Unit {
// ...
}
//////////////////////////////////////////////////////////////////
// Part IV. Teleportation with three entangled qubits
//////////////////////////////////////////////////////////////////
// Quantum teleportation using entangled states other than Bell pairs is also feasible.
// Here we look at just one of many possible schemes - in it a state is transferred from
// Alice to a third participant Charlie, but this may only be accomplished if Charlie
// Alice to a third participant Charlie, but this may only be accomplished if Charlie
// has the trust of the second participant Bob.
// Task 4.1*. Entangled trio
// Input: three qubits qAlice, qBob, and qCharlie, each in |0⟩ state.
// Goal: create an entangled state |Ψ³⟩ = (|000⟩ + |011⟩ + |101⟩ + |110⟩) / 2 on these qubits.
//
// In the context of the quantum teleportation protocol, this is the preparation step:
// qubits qAlice, qBob, and qCharlie will be sent to Alice, Bob, and Charlie respectively.
operation EntangleThreeQubits (qAlice : Qubit, qBob : Qubit, qCharlie : Qubit) : ()
{
body {
// ...
}
// qubits qAlice, qBob, and qCharlie will be sent to Alice, Bob, and Charlie respectively.
operation EntangleThreeQubits (qAlice : Qubit, qBob : Qubit, qCharlie : Qubit) : Unit {
// ...
}
// Task 4.2*. Reconstruct the message (Charlie's task)
// Alice has a message qubit in the state |ψ⟩ to be teleported, she has entangled it with
// Alice has a message qubit in the state |ψ⟩ to be teleported, she has entangled it with
// her own qubit from |Ψ³⟩ in the same manner as task 1.2 and extracted two classical bits
// in order to send them to Charlie. Bob has also measured his own qubit from |Ψ³⟩ and sent
// in order to send them to Charlie. Bob has also measured his own qubit from |Ψ³⟩ and sent
// Charlie the result.
//
// Transform Charlie's qubit into the required state using the two classical bits
// received from Alice, and the one classical bit received from Bob.
// Inputs:
// 1) Charlie's part of the entangled trio of qubits qCharlie.
// 2) The tuple of classical bits received from Alice,
// 2) The tuple of classical bits received from Alice,
// in the format used in task 1.2.
// 3) A classical bit resulting from the measurement of Bob's qubit.
// Goal: transform Charlie's qubit qCharlie into the state in which the message qubit had been originally.
operation ReconstructMessageWhenThreeEntangledQubits (qCharlie : Qubit, (b1 : Bool, b2 : Bool), b3 : Bool) : ()
{
body {
// ...
}
operation ReconstructMessageWhenThreeEntangledQubits (qCharlie : Qubit, (b1 : Bool, b2 : Bool), b3 : Bool) : Unit {
// ...
}
}

Просмотреть файл

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<IsPackable>false</IsPackable>
<RootNamespace>Quantum.Kata.Teleportation</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.2.1809.701-preview" />
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.3.1810.2508-preview" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

Просмотреть файл

@ -1,352 +1,290 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains testing harness for all tasks.
// This file contains testing harness for all tasks.
// You should not modify anything in this file.
// The tasks themselves can be found in Tasks.qs file.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.Teleportation
{
namespace Quantum.Kata.Teleportation {
open Microsoft.Quantum.Primitive;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Extensions.Testing;
// ------------------------------------------------------
operation T11_Entangle_Test () : ()
{
body
{
using (qs = Qubit[2])
{
let q0 = qs[0];
let q1 = qs[1];
// Apply operation that needs to be tested
Entangle(q0, q1);
// Apply adjoint reference operation and check that the result is |00⟩
(Adjoint Entangle_Reference)(q0, q1);
// Assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
operation T11_Entangle_Test () : Unit {
using (qs = Qubit[2]) {
let q0 = qs[0];
let q1 = qs[1];
// Apply operation that needs to be tested
Entangle(q0, q1);
// Apply adjoint reference operation and check that the result is |00⟩
Adjoint Entangle_Reference(q0, q1);
// Assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
// ------------------------------------------------------
// Helper which prepares proper Bell state on two qubits
// 0 - |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
// 1 - |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
// 2 - |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
// 3 - |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
operation StatePrep_BellState (q1 : Qubit, q2 : Qubit, state : Int) : () {
body {
H(q1);
CNOT(q1, q2);
// now we have |00⟩ + |11⟩ - modify it based on state arg
if (state % 2 == 1) {
// negative phase
Z(q2);
}
if (state / 2 == 1) {
X(q2);
}
operation StatePrep_BellState (q1 : Qubit, q2 : Qubit, state : Int) : Unit {
H(q1);
CNOT(q1, q2);
// now we have |00⟩ + |11⟩ - modify it based on state arg
if (state % 2 == 1) {
// negative phase
Z(q2);
}
if (state / 2 == 1) {
X(q2);
}
}
// ------------------------------------------------------
// Helper operation that runs teleportation using two building blocks
// specified as first two parameters.
operation ComposeTeleportation(
bellPrepOp : ((Qubit, Qubit) => ()),
getDescriptionOp : ((Qubit, Qubit) => (Bool, Bool)),
reconstructOp : ((Qubit, (Bool, Bool)) => ()),
qAlice : Qubit,
qBob : Qubit,
qMessage : Qubit
) : ()
{
body
{
bellPrepOp(qAlice, qBob);
let classicalBits = getDescriptionOp(qAlice, qMessage);
// Alice sends the classical bits to Bob.
// Bob uses these bits to transform his part of the entangled pair into the message.
reconstructOp(qBob, classicalBits);
}
operation ComposeTeleportation (
bellPrepOp : ((Qubit, Qubit) => Unit),
getDescriptionOp : ((Qubit, Qubit) => (Bool, Bool)),
reconstructOp : ((Qubit, (Bool, Bool)) => Unit),
qAlice : Qubit,
qBob : Qubit,
qMessage : Qubit) : Unit {
bellPrepOp(qAlice, qBob);
let classicalBits = getDescriptionOp(qAlice, qMessage);
// Alice sends the classical bits to Bob.
// Bob uses these bits to transform his part of the entangled pair into the message.
reconstructOp(qBob, classicalBits);
}
// ------------------------------------------------------
// Helper operation that runs a teleportation operation (specified by teleportOp).
// Helper operation that runs a teleportation operation (specified by teleportOp).
// The state to teleport is set up using an operation (specified by setupPsiOp).
//
// Specifying the state to teleport through an operation allows to get the inverse
// which makes testing easier.
operation TeleportTestHelper(
teleportOp : ((Qubit, Qubit, Qubit) => ()),
setupPsiOp : (Qubit => () : Adjoint)
) : ()
{
body{
using(qs = Qubit[3])
{
let qMessage = qs[0];
let qAlice = qs[1];
let qBob = qs[2];
setupPsiOp(qMessage);
// This should modify qBob to be identical to the state
// of qMessage before the function call.
teleportOp(qAlice, qBob, qMessage);
// Applying the inverse of the setup operation to qBob
// should make it Zero.
(Adjoint setupPsiOp)(qBob);
AssertQubit(Zero, qBob);
ResetAll(qs);
}
operation TeleportTestHelper (
teleportOp : ((Qubit, Qubit, Qubit) => Unit),
setupPsiOp : (Qubit => Unit : Adjoint)) : Unit {
using (qs = Qubit[3]) {
let qMessage = qs[0];
let qAlice = qs[1];
let qBob = qs[2];
setupPsiOp(qMessage);
// This should modify qBob to be identical to the state
// of qMessage before the function call.
teleportOp(qAlice, qBob, qMessage);
// Applying the inverse of the setup operation to qBob
// should make it Zero.
Adjoint setupPsiOp(qBob);
AssertQubit(Zero, qBob);
ResetAll(qs);
}
}
// ------------------------------------------------------
// Run teleportation for a number of different states.
// After each teleportation success is asserted.
// Also repeats for each state several times as
// Also repeats for each state several times as
// code is expected to take different paths each time because
// measurements done by Alice are not deterministic.
operation TeleportTestLoop(teleportOp : ((Qubit, Qubit, Qubit) => ())) : ()
{
body
{
// Define setup operations for the message qubit
// on which to test teleportation: |0⟩, |1⟩, |0⟩ + |1⟩, unequal superposition.
let setupPsiOps = [I; X; H; Ry(42.0, _)];
// As part of teleportation Alice runs some measurements
// with nondeterministic outcome.
// Depending on the outcomes different paths are taken on Bob's side.
// We repeat each test run several times to ensure that all paths are checked.
let numRepetitions = 100;
for (i in 0..Length(setupPsiOps)-1)
{
for (j in 1..numRepetitions)
{
TeleportTestHelper(teleportOp, setupPsiOps[i]);
}
operation TeleportTestLoop (teleportOp : ((Qubit, Qubit, Qubit) => Unit)) : Unit {
// Define setup operations for the message qubit
// on which to test teleportation: |0⟩, |1⟩, |0⟩ + |1⟩, unequal superposition.
let setupPsiOps = [I, X, H, Ry(42.0, _)];
// As part of teleportation Alice runs some measurements
// with nondeterministic outcome.
// Depending on the outcomes different paths are taken on Bob's side.
// We repeat each test run several times to ensure that all paths are checked.
let numRepetitions = 100;
for (i in 0 .. Length(setupPsiOps) - 1) {
for (j in 1 .. numRepetitions) {
TeleportTestHelper(teleportOp, setupPsiOps[i]);
}
}
}
// Test the 'SendMessage' operation by using it as one part of full teleportation,
// Test the 'SendMessage' operation by using it as one part of full teleportation,
// taking reference implementation for the other parts.
operation T12_SendMessage_Test() : ()
{
body
{
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 0), SendMessage, ReconstructMessage_Reference, _, _ , _);
TeleportTestLoop(teleport);
}
operation T12_SendMessage_Test () : Unit {
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 0), SendMessage, ReconstructMessage_Reference, _, _, _);
TeleportTestLoop(teleport);
}
// Test the 'ReconstructMessage' operation by using it as one part of full teleportation,
// taking reference implementation for the other parts.
operation T13_ReconstructMessage_Test() : ()
{
body
{
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 0), SendMessage_Reference, ReconstructMessage, _, _ , _);
TeleportTestLoop(teleport);
}
operation T13_ReconstructMessage_Test () : Unit {
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 0), SendMessage_Reference, ReconstructMessage, _, _, _);
TeleportTestLoop(teleport);
}
// Test the full Teleport operation
operation T14_Teleport_Test() : ()
{
body
{
TeleportTestLoop(StandardTeleport);
}
operation T14_Teleport_Test () : Unit {
TeleportTestLoop(StandardTeleport);
}
// ------------------------------------------------------
// Runs teleportation for each state that is to be prepared and
// sent by Alice. Success is asserted after each teleportation.
// Also repeats for each state several times; this is because
// Also repeats for each state several times; this is because
// code is expected to take different paths each time since
// measurements done by Alice are not deterministic.
operation TeleportPreparedStateTestLoop(
prepareAndSendMessageOp : ((Qubit, Pauli, Bool) => (Bool, Bool)),
reconstructAndMeasureMessageOp : ((Qubit, (Bool, Bool), Pauli) => (Bool))
) : ()
{
body
{
let messages = [(PauliX, false); (PauliX, true); (PauliY, false); (PauliY, true); (PauliZ, false); (PauliZ, true)];
let numRepetitions = 100;
using(qs = Qubit[2])
{
let qAlice = qs[0];
let qBob = qs[1];
for (i in 0..Length(messages)-1)
{
for (j in 1..numRepetitions)
{
let (basis, sentState) = messages[i];
StatePrep_BellState(qAlice, qBob, 0);
let classicalBits = prepareAndSendMessageOp(qAlice, basis, sentState);
let receivedState = reconstructAndMeasureMessageOp(qBob, classicalBits, basis);
AssertBoolEqual(receivedState, sentState, $"Sent and received states were not equal for {sentState} eigenstate in {basis} basis.");
ResetAll(qs);
}
operation TeleportPreparedStateTestLoop (prepareAndSendMessageOp : ((Qubit, Pauli, Bool) => (Bool, Bool)), reconstructAndMeasureMessageOp : ((Qubit, (Bool, Bool), Pauli) => Bool)) : Unit {
let messages = [(PauliX, false),
(PauliX, true),
(PauliY, false),
(PauliY, true),
(PauliZ, false),
(PauliZ, true)];
let numRepetitions = 100;
using (qs = Qubit[2]) {
let qAlice = qs[0];
let qBob = qs[1];
for (i in 0 .. Length(messages) - 1) {
for (j in 1 .. numRepetitions) {
let (basis, sentState) = messages[i];
StatePrep_BellState(qAlice, qBob, 0);
let classicalBits = prepareAndSendMessageOp(qAlice, basis, sentState);
let receivedState = reconstructAndMeasureMessageOp(qBob, classicalBits, basis);
AssertBoolEqual(receivedState, sentState, $"Sent and received states were not equal for {sentState} eigenstate in {basis} basis.");
ResetAll(qs);
}
}
}
}
// Test the 'PrepareAndSendMessage' operation by using it as one part of full teleportation,
// Test the 'PrepareAndSendMessage' operation by using it as one part of full teleportation,
// taking reference implementation for the other parts.
operation T15_PrepareAndSendMessage_Test() : ()
{
body
{
TeleportPreparedStateTestLoop(PrepareAndSendMessage, ReconstructAndMeasureMessage_Reference);
}
operation T15_PrepareAndSendMessage_Test () : Unit {
TeleportPreparedStateTestLoop(PrepareAndSendMessage, ReconstructAndMeasureMessage_Reference);
}
// Test the 'ReconstructAndMeasureMessage' operation by using it as one part of full teleportation,
// taking reference implementation for the other parts.
operation T16_ReconstructAndMeasureMessage_Test() : ()
{
body
{
TeleportPreparedStateTestLoop(PrepareAndSendMessage_Reference, ReconstructAndMeasureMessage);
}
operation T16_ReconstructAndMeasureMessage_Test () : Unit {
TeleportPreparedStateTestLoop(PrepareAndSendMessage_Reference, ReconstructAndMeasureMessage);
}
// ------------------------------------------------------
// Test variations of the teleport protocol using different state prep procedures
operation T21_ReconstructMessage_PhiMinus_Test() : ()
{
body
{
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 1), SendMessage_Reference, ReconstructMessage_PhiMinus, _, _ , _);
TeleportTestLoop(teleport);
}
operation T21_ReconstructMessage_PhiMinus_Test () : Unit {
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 1), SendMessage_Reference, ReconstructMessage_PhiMinus, _, _, _);
TeleportTestLoop(teleport);
}
operation T22_ReconstructMessage_PsiPlus_Test() : ()
{
body
{
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 2), SendMessage_Reference, ReconstructMessage_PsiPlus, _, _ , _);
TeleportTestLoop(teleport);
}
operation T22_ReconstructMessage_PsiPlus_Test () : Unit {
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 2), SendMessage_Reference, ReconstructMessage_PsiPlus, _, _, _);
TeleportTestLoop(teleport);
}
operation T23_ReconstructMessage_PsiMinus_Test() : ()
{
body
{
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 3), SendMessage_Reference, ReconstructMessage_PsiMinus, _, _ , _);
TeleportTestLoop(teleport);
}
operation T23_ReconstructMessage_PsiMinus_Test () : Unit {
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 3), SendMessage_Reference, ReconstructMessage_PsiMinus, _, _, _);
TeleportTestLoop(teleport);
}
// ------------------------------------------------------
operation T31_MeasurementFreeTeleport_Test() : ()
{
body
{
let setupPsiOps = [I; X; H; Ry(42.0, _)];
let numRepetitions = 100;
using(qs = Qubit[3])
{
let qMessage = qs[0];
let qAlice = qs[1];
let qBob = qs[2];
for (i in 0..Length(setupPsiOps)-1)
{
for (j in 1..numRepetitions)
{
(setupPsiOps[i])(qMessage);
StatePrep_BellState(qAlice, qBob, 0);
MeasurementFreeTeleport(qAlice, qBob, qMessage);
(Adjoint setupPsiOps[i])(qBob);
AssertQubit(Zero, qBob);
ResetAll(qs);
}
}
}
}
}
// ------------------------------------------------------
operation T41_EntangleThreeQubits_Test() : ()
{
body
{
using (qs = Qubit[3])
{
let qAlice = qs[0];
let qBob = qs[1];
let qCharlie = qs[2];
// Apply operation that needs to be tested
EntangleThreeQubits(qAlice, qBob, qCharlie);
// Apply adjoint reference operation and check that the result is |000⟩
(Adjoint EntangleThreeQubits_Reference)(qAlice, qBob, qCharlie);
// Assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
}
operation T42_ReconstructMessageWhenThreeEntangledQubits_Test() : ()
{
body
{
let setupPsiOps = [I; X; H; Ry(42.0, _)];
let numRepetitions = 100;
using (qs = Qubit[4])
{
let qMessage = qs[0];
let qAlice = qs[1];
let qBob = qs[2];
let qCharlie = qs[3];
operation T31_MeasurementFreeTeleport_Test () : Unit {
let setupPsiOps = [I, X, H, Ry(42.0, _)];
let numRepetitions = 100;
using (qs = Qubit[3]) {
let qMessage = qs[0];
let qAlice = qs[1];
let qBob = qs[2];
for (i in 0..Length(setupPsiOps)-1)
{
for (j in 1..numRepetitions)
{
(setupPsiOps[i])(qMessage);
EntangleThreeQubits_Reference(qAlice, qBob, qCharlie);
let (b1, b2) = SendMessage_Reference(qAlice, qMessage);
let b3 = BoolFromResult(M(qBob));
ReconstructMessageWhenThreeEntangledQubits(qCharlie, (b1, b2), b3);
(Adjoint setupPsiOps[i])(qCharlie);
AssertQubit(Zero, qCharlie);
ResetAll(qs);
}
for (i in 0 .. Length(setupPsiOps) - 1) {
for (j in 1 .. numRepetitions) {
setupPsiOps[i](qMessage);
StatePrep_BellState(qAlice, qBob, 0);
MeasurementFreeTeleport(qAlice, qBob, qMessage);
Adjoint setupPsiOps[i](qBob);
AssertQubit(Zero, qBob);
ResetAll(qs);
}
}
}
}
// ------------------------------------------------------
operation T41_EntangleThreeQubits_Test () : Unit {
using (qs = Qubit[3]) {
let qAlice = qs[0];
let qBob = qs[1];
let qCharlie = qs[2];
// Apply operation that needs to be tested
EntangleThreeQubits(qAlice, qBob, qCharlie);
// Apply adjoint reference operation and check that the result is |000⟩
Adjoint EntangleThreeQubits_Reference(qAlice, qBob, qCharlie);
// Assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}
operation T42_ReconstructMessageWhenThreeEntangledQubits_Test () : Unit {
let setupPsiOps = [I, X, H, Ry(42.0, _)];
let numRepetitions = 100;
using (qs = Qubit[4]) {
let qMessage = qs[0];
let qAlice = qs[1];
let qBob = qs[2];
let qCharlie = qs[3];
for (i in 0 .. Length(setupPsiOps) - 1) {
for (j in 1 .. numRepetitions) {
setupPsiOps[i](qMessage);
EntangleThreeQubits_Reference(qAlice, qBob, qCharlie);
let (b1, b2) = SendMessage_Reference(qAlice, qMessage);
let b3 = BoolFromResult(M(qBob));
ReconstructMessageWhenThreeEntangledQubits(qCharlie, (b1, b2), b3);
Adjoint setupPsiOps[i](qCharlie);
AssertQubit(Zero, qCharlie);
ResetAll(qs);
}
}
}
}
}