285 строки
11 KiB
Plaintext
285 строки
11 KiB
Plaintext
// 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.Teleportation {
|
|
|
|
open Microsoft.Quantum.Primitive;
|
|
open Microsoft.Quantum.Canon;
|
|
open Microsoft.Quantum.Extensions.Testing;
|
|
|
|
|
|
// ------------------------------------------------------
|
|
operation T11_Entangle_Test () : Unit {
|
|
using ((q0, q1) = (Qubit(), Qubit())) {
|
|
// 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([q0, q1]);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------
|
|
// 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) : 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) => 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).
|
|
// 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) => 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
|
|
// code is expected to take different paths each time because
|
|
// measurements done by Alice are not deterministic.
|
|
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,
|
|
// taking reference implementation for the other parts.
|
|
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 () : Unit {
|
|
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 0), SendMessage_Reference, ReconstructMessage, _, _, _);
|
|
TeleportTestLoop(teleport);
|
|
}
|
|
|
|
|
|
// Test the full Teleport operation
|
|
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
|
|
// 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)) : Unit {
|
|
|
|
let messages = [(PauliX, false),
|
|
(PauliX, true),
|
|
(PauliY, false),
|
|
(PauliY, true),
|
|
(PauliZ, false),
|
|
(PauliZ, true)];
|
|
let numRepetitions = 100;
|
|
|
|
using ((qAlice, qBob) = (Qubit(), Qubit())) {
|
|
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([qAlice, qBob]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Test the 'PrepareAndSendMessage' operation by using it as one part of full teleportation,
|
|
// taking reference implementation for the other parts.
|
|
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 () : Unit {
|
|
TeleportPreparedStateTestLoop(PrepareAndSendMessage_Reference, ReconstructAndMeasureMessage);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------
|
|
// Test variations of the teleport protocol using different state prep procedures
|
|
operation T21_ReconstructMessage_PhiMinus_Test () : Unit {
|
|
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 1), SendMessage_Reference, ReconstructMessage_PhiMinus, _, _, _);
|
|
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 () : Unit {
|
|
let teleport = ComposeTeleportation(StatePrep_BellState(_, _, 3), SendMessage_Reference, ReconstructMessage_PsiMinus, _, _, _);
|
|
TeleportTestLoop(teleport);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------
|
|
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);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|