Superdense Coding Kata
Co-authored-by: Mario Inchiosa <4316698+inchiosa@users.noreply.github.com> Co-authored-by: Ricardo Espinoza <ricardoe@outlook.com>
This commit is contained in:
Родитель
54ae7015a9
Коммит
a1dd88caf6
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"quantum.quantum-devkit-vscode"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build"
|
||||
],
|
||||
"type": "process",
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "test",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"test"
|
||||
],
|
||||
"type": "process",
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
# Welcome!
|
||||
|
||||
This kata covers superdense coding - a protocol which allows to transmit two bits of classical information by sending just one qubit using previously shared quantum entanglement. This protocol can be thought of as the dual to the teleportation protocol, which allows to transfer the state of a qubit by sending two classical bits.
|
||||
|
||||
- A good description can be found in [the Wikipedia article](https://en.wikipedia.org/wiki/Superdense_coding).
|
||||
- Superdense coding protocol is described in Nielsen & Chuang, section 2.3 (pp. 97-98).
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
{
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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); }
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</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.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27428.2043
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperdenseCoding", "SuperdenseCoding.csproj", "{66D2BB70-C6A1-429E-AD4B-F869589FF3DB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{66D2BB70-C6A1-429E-AD4B-F869589FF3DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{66D2BB70-C6A1-429E-AD4B-F869589FF3DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{66D2BB70-C6A1-429E-AD4B-F869589FF3DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{66D2BB70-C6A1-429E-AD4B-F869589FF3DB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {4866C0EE-45B5-49C8-BBCB-9AA5305BAA47}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,113 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
// 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.");
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
// 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:
|
||||
// [0; 0]: |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2)
|
||||
// [0; 1]: |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
|
||||
// [1; 0]: |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
|
||||
// [1; 1]: |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// Task 3. Decode the message (Bob's task)
|
||||
// Decode the message using the qubit received from Alice.
|
||||
// Inputs:
|
||||
// 1) Bob's part of the entangled pair qBob.
|
||||
// 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];
|
||||
|
||||
// ...
|
||||
|
||||
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];
|
||||
|
||||
// ...
|
||||
|
||||
return decoded_bits;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
using Microsoft.Quantum.Simulation.XUnit;
|
||||
using Microsoft.Quantum.Simulation.Simulators;
|
||||
using Xunit.Abstractions;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Quantum.Kata.SuperdenseCoding
|
||||
{
|
||||
public class TestSuiteRunner
|
||||
{
|
||||
private readonly ITestOutputHelper output;
|
||||
|
||||
public TestSuiteRunner(ITestOutputHelper output)
|
||||
{
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This driver will run all Q# tests (operations named "...Test")
|
||||
/// that belong to namespace Quantum.Kata.SuperdenseCoding.
|
||||
/// </summary>
|
||||
[OperationDriver(TestNamespace = "Quantum.Kata.SuperdenseCoding")]
|
||||
public void TestTarget(TestOperation op)
|
||||
{
|
||||
using (var sim = new QuantumSimulator())
|
||||
{
|
||||
// OnLog defines action(s) performed when Q# test calls function Message
|
||||
sim.OnLog += (msg) => { output.WriteLine(msg); };
|
||||
sim.OnLog += (msg) => { Debug.WriteLine(msg); };
|
||||
op.TestOperationRunner(sim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
{
|
||||
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 T1_CreateEntangledPair_Test () : ()
|
||||
{
|
||||
body
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
// 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 T2_EncodeMessageInQubit_Test () : ()
|
||||
{
|
||||
body
|
||||
{
|
||||
TestProtocol(ComposeProtocol(EncodeMessageInQubit, DecodeMessageFromQubits_Reference, _));
|
||||
}
|
||||
}
|
||||
|
||||
operation T3_DecodeMessageFromQubits_Test () : ()
|
||||
{
|
||||
body
|
||||
{
|
||||
TestProtocol(ComposeProtocol(EncodeMessageInQubit_Reference, DecodeMessageFromQubits, _));
|
||||
}
|
||||
}
|
||||
|
||||
operation T4_SuperdenseCodingProtocol_Test () : ()
|
||||
{
|
||||
body
|
||||
{
|
||||
TestProtocol(SuperdenseCodingProtocol);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче