Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.

update tests for basic gates #300

Merged
merged 6 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions BasicGates/ReferenceImplementation.qs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ namespace Quantum.Kata.BasicGates {
// 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
// of the states of individual qubits any longer; thus the qubits become entangled.
operation TwoQubitGate1_Reference (qs : Qubit[]) : Unit is Adj {
operation TwoQubitGate1_Reference (qs : Qubit[]) : Unit is Adj+Ctl {
CNOT(qs[0], qs[1]);
}

Expand All @@ -140,7 +140,7 @@ namespace Quantum.Kata.BasicGates {
// 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[]) : Unit is Adj {
operation TwoQubitGate2_Reference (qs : Qubit[]) : Unit is Adj+Ctl {
Controlled Z([qs[0]], qs[1]);
// alternatively: CZ(qs[0], qs[1]);
}
Expand All @@ -149,7 +149,7 @@ namespace Quantum.Kata.BasicGates {
// 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[]) : Unit is Adj {
operation TwoQubitGate3_Reference (qs : Qubit[]) : Unit is Adj+Ctl {
// Hint: this task can be solved using one intrinsic gate;
// as an exercise, try to express the solution using several controlled Pauli gates.
CNOT(qs[0], qs[1]);
Expand All @@ -164,7 +164,7 @@ namespace Quantum.Kata.BasicGates {
// 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[]) : Unit is Adj {
operation ToffoliGate_Reference (qs : Qubit[]) : Unit is Adj+Ctl {
CCNOT(qs[0], qs[1], qs[2]);
// alternatively (Controlled X)(qs[0..1], qs[2]);
}
Expand All @@ -175,7 +175,7 @@ namespace Quantum.Kata.BasicGates {
// 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
// α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + η|101⟩ + ζ|110⟩ + θ|111⟩.
operation FredkinGate_Reference (qs : Qubit[]) : Unit is Adj {
operation FredkinGate_Reference (qs : Qubit[]) : Unit is Adj+Ctl {
Controlled SWAP([qs[0]], (qs[1], qs[2]));
}

Expand Down
10 changes: 5 additions & 5 deletions BasicGates/Tasks.qs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ namespace Quantum.Kata.BasicGates {
// 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
// of the states of individual qubits any longer; thus the qubits become entangled.
operation TwoQubitGate1 (qs : Qubit[]) : Unit is Adj {
operation TwoQubitGate1 (qs : Qubit[]) : Unit is Adj+Ctl {
// ...
}

Expand All @@ -173,7 +173,7 @@ namespace Quantum.Kata.BasicGates {
// 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[]) : Unit is Adj {
operation TwoQubitGate2 (qs : Qubit[]) : Unit is Adj+Ctl {
// ...
}

Expand All @@ -182,7 +182,7 @@ namespace Quantum.Kata.BasicGates {
// 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[]) : Unit is Adj {
operation TwoQubitGate3 (qs : Qubit[]) : Unit is Adj+Ctl {
// Hint: this task can be solved using one intrinsic gate;
// as an exercise, try to express the solution using several
// (possibly controlled) Pauli gates.
Expand All @@ -196,7 +196,7 @@ namespace Quantum.Kata.BasicGates {
// 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[]) : Unit is Adj {
operation ToffoliGate (qs : Qubit[]) : Unit is Adj+Ctl {
// ...
}

Expand All @@ -206,7 +206,7 @@ namespace Quantum.Kata.BasicGates {
// α|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[]) : Unit is Adj {
operation FredkinGate (qs : Qubit[]) : Unit is Adj+Ctl {
// ...
}

Expand Down
160 changes: 123 additions & 37 deletions BasicGates/Tests.qs
Original file line number Diff line number Diff line change
Expand Up @@ -26,59 +26,137 @@ namespace Quantum.Kata.BasicGates {
// so the tests use controlled version of the operations which converts the global phase into a relative phase
// and makes it possible to detect.

// ------------------------------------------------------
// Helper wrapper to represent operation on one qubit
// as an operation on an array of one qubits
operation ArrayWrapper (op : (Qubit => Unit is Adj+Ctl), qs : Qubit[]) : Unit is Adj+Ctl {
op(qs[0]);
}

// ------------------------------------------------------
// Helper wrapper to represent controlled variant of operation on one qubit
// as an operation on an array of two qubits
operation ArrayWrapperOperation (op : (Qubit => Unit is Adj+Ctl), qs : Qubit[]) : Unit is Adj+Ctl {
operation ArrayWrapperControlled (op : (Qubit => Unit is Adj+Ctl), qs : Qubit[]) : Unit is Adj+Ctl {
Controlled op([qs[0]], qs[1]);
}




// ------------------------------------------------------
// Helper operation to show the difference between the reference solution and the learner's one
operation DumpDiff (N : Int,
statePrep : (Qubit[] => Unit is Adj+Ctl),
testImpl : (Qubit[] => Unit is Adj+Ctl),
refImpl : (Qubit[] => Unit is Adj+Ctl)
) : Unit {
using (qs = Qubit[N]) {
// Prepare the input state and show it
statePrep(qs);
Message("The starting state:");
DumpMachine();

// Apply the reference solution and show result
refImpl(qs);
Message("The desired state:");
DumpMachine();
ResetAll(qs);

// Prepare the input state again for test implementation
statePrep(qs);
// Apply learner's solution and show result
testImpl(qs);
Message("The actual state:");
DumpMachine();
ResetAll(qs);
}
}


// Used for single-qubit operations that are unlikely to introduce the extra global phase
operation DumpDiffOnOneQubit (testImpl : (Qubit => Unit is Adj+Ctl),
refImpl : (Qubit => Unit is Adj+Ctl)) : Unit {
DumpDiff(1, ArrayWrapper(Ry(2.0 * ArcCos(0.6), _), _),
ArrayWrapper(testImpl, _),
ArrayWrapper(refImpl, _));
}


// ------------------------------------------------------
operation T101_StateFlip_Test () : Unit {
AssertOperationsEqualReferenced(2, ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _));
DumpDiffOnOneQubit(StateFlip, StateFlip_Reference);
AssertOperationsEqualReferenced(2, ArrayWrapperControlled(StateFlip, _),
ArrayWrapperControlled(StateFlip_Reference, _));
}


// ------------------------------------------------------
operation T102_BasisChange_Test () : Unit {
AssertOperationsEqualReferenced(2, ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _));
DumpDiffOnOneQubit(BasisChange, BasisChange_Reference);
AssertOperationsEqualReferenced(2, ArrayWrapperControlled(BasisChange, _),
ArrayWrapperControlled(BasisChange_Reference, _));
}


// ------------------------------------------------------
operation T103_SignFlip_Test () : Unit {
AssertOperationsEqualReferenced(2, ArrayWrapperOperation(SignFlip, _), ArrayWrapperOperation(SignFlip_Reference, _));
DumpDiffOnOneQubit(SignFlip, SignFlip_Reference);
AssertOperationsEqualReferenced(2, ArrayWrapperControlled(SignFlip, _),
ArrayWrapperControlled(SignFlip_Reference, _));
}


// ------------------------------------------------------
operation T104_AmplitudeChange_Test () : Unit {
// pick one rotation angle on which to show difference between solutions
let dumpAlpha = ((2.0 * PI()) * IntAsDouble(6)) / 36.0;
Message($"Applying amplitude change with alpha = {dumpAlpha}");
DumpDiffOnOneQubit(AmplitudeChange(dumpAlpha, _), AmplitudeChange_Reference(dumpAlpha, _));

for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
AssertOperationsEqualReferenced(2, ArrayWrapperOperation(AmplitudeChange(alpha, _), _), ArrayWrapperOperation(AmplitudeChange_Reference(alpha, _), _));
AssertOperationsEqualReferenced(2, ArrayWrapperControlled(AmplitudeChange(alpha, _), _),
ArrayWrapperControlled(AmplitudeChange_Reference(alpha, _), _));
}
}


// ------------------------------------------------------
operation T105_PhaseFlip_Test () : Unit {
AssertOperationsEqualReferenced(2, ArrayWrapperOperation(PhaseFlip, _), ArrayWrapperOperation(PhaseFlip_Reference, _));
DumpDiffOnOneQubit(PhaseFlip, PhaseFlip_Reference);
AssertOperationsEqualReferenced(2, ArrayWrapperControlled(PhaseFlip, _),
ArrayWrapperControlled(PhaseFlip_Reference, _));
}


// ------------------------------------------------------
operation T106_PhaseChange_Test () : Unit {
let dumpAlpha = ((2.0 * PI()) * IntAsDouble(10)) / 36.0;
Message($"Applying phase change with alpha = {dumpAlpha}");
DumpDiffOnOneQubit(PhaseChange(dumpAlpha,_), PhaseChange_Reference(dumpAlpha,_));

for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
AssertOperationsEqualReferenced(2, ArrayWrapperOperation(PhaseChange(alpha, _), _), ArrayWrapperOperation(PhaseChange_Reference(alpha, _), _));
AssertOperationsEqualReferenced(2, ArrayWrapperControlled(PhaseChange(alpha, _), _),
ArrayWrapperControlled(PhaseChange_Reference(alpha, _), _));
}
}


// ------------------------------------------------------
// State prep for showing the controlled version of single-qubit operation
operation StatePrepForControlled (qs : Qubit[]) : Unit is Adj+Ctl {
H(qs[0]);
Ry(2.0 * ArcCos(0.6), qs[1]);
}

operation T107_GlobalPhaseChange_Test () : Unit {
AssertOperationsEqualReferenced(2, ArrayWrapperOperation(GlobalPhaseChange, _), ArrayWrapperOperation(GlobalPhaseChange_Reference, _));
// use the controlled version of unitaries for showing the difference, since it's hard to observe on non-controlled versions
Message("Showing effect of controlled-GlobalPhaseChange");
DumpDiff(2, StatePrepForControlled,
ArrayWrapperControlled(GlobalPhaseChange, _),
ArrayWrapperControlled(GlobalPhaseChange_Reference, _));

AssertOperationsEqualReferenced(2, ArrayWrapperControlled(GlobalPhaseChange, _),
ArrayWrapperControlled(GlobalPhaseChange_Reference, _));
}


Expand Down Expand Up @@ -126,45 +204,46 @@ namespace Quantum.Kata.BasicGates {
}
}



// ------------------------------------------------------
operation T108_BellStateChange1_Test () : Unit {
DumpDiff(2, StatePrep_BellState(_, 0), BellStateChange1, BellStateChange1_Reference);
VerifyBellStateConversion(BellStateChange1, 0, 1);
}


// ------------------------------------------------------
operation T109_BellStateChange2_Test () : Unit {
DumpDiff(2, StatePrep_BellState(_, 0), BellStateChange2, BellStateChange2_Reference);
VerifyBellStateConversion(BellStateChange2, 0, 2);
}


// ------------------------------------------------------
operation T110_BellStateChange3_Test () : Unit {
DumpDiff(2, StatePrep_BellState(_, 0), BellStateChange3, BellStateChange3_Reference);
Message("If the desired and the actual states match but the test doesn't pass, check whether your solution introduces a global phase; it shouldn't!");
VerifyBellStateConversion(BellStateChange3, 0, 3);
}


// ------------------------------------------------------
// prepare state |A⟩ = cos(α) * |0⟩ + sin(α) * |1⟩
operation StatePrep_A (alpha : Double, q : Qubit) : Unit is Adj {
Ry(2.0 * alpha, q);
operation StatePrepRy (qs : Qubit[]) : Unit is Adj+Ctl {
Ry(2.0 * (2.0 * PI() * 6.0) / 36.0, Head(qs));
}


// ------------------------------------------------------

operation T201_TwoQubitGate1_Test () : Unit {

DumpDiff(2, StatePrepRy, TwoQubitGate1, TwoQubitGate1_Reference);

// 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
// we need to create a specific input state and check that the output state is correct
using (qs = Qubit[2]) {
for (i in 0 .. 36) {
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;

within {
// prepare A state
StatePrep_A(alpha, qs[0]);
// prepare state cos(α) * |0⟩ + sin(α) * |1⟩
Ry(2.0 * alpha, qs[0]);
}
apply {
// apply operation that needs to be tested
Expand All @@ -181,53 +260,60 @@ namespace Quantum.Kata.BasicGates {
}


// ------------------------------------------------------
// prepare state |+⟩ ⊗ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2.
operation StatePrep_PlusPlus (qs : Qubit[]) : Unit is Adj {
ApplyToEachA(H, qs);
}


// ------------------------------------------------------
operation T202_TwoQubitGate2_Test () : Unit {
DumpDiff(2, ApplyToEachCA(H, _), TwoQubitGate2, TwoQubitGate2_Reference);
using (qs = Qubit[2]) {
// prepare |+⟩ ⊗ |+⟩ state
StatePrep_PlusPlus(qs);

// apply operation that needs to be tested
TwoQubitGate2(qs);
within {
// prepare |+⟩ ⊗ |+⟩ state
ApplyToEachCA(H, qs);
} apply {
// 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);
// apply adjoint reference operation
Adjoint TwoQubitGate2_Reference(qs);
}

// assert that all qubits end up in |0⟩ state
AssertAllZero(qs);
}
}


// ------------------------------------------------------
// Prepare a state for tests 2.3-2.5
operation StatePrepMiscAmplitudes (qs : Qubit[]) : Unit is Adj+Ctl {
let alphas = [5.0, 10.0, 15.0];
for (index in 0 .. Length(qs) - 1) {
Ry(2.0 * (alphas[index] + IntAsDouble(index + 1)), qs[index]);
}
}


// ------------------------------------------------------
operation SwapWrapper (qs : Qubit[]) : Unit is Adj {
SWAP(qs[0], qs[1]);
}


operation T203_TwoQubitGate3_Test () : Unit {
DumpDiff(2, StatePrepMiscAmplitudes, TwoQubitGate3, TwoQubitGate3_Reference);
AssertOperationsEqualReferenced(2, SwapWrapper, TwoQubitGate3_Reference);
AssertOperationsEqualReferenced(2, TwoQubitGate3, TwoQubitGate3_Reference);
}


// ------------------------------------------------------
operation T204_ToffoliGate_Test () : Unit {
DumpDiff(2, StatePrepMiscAmplitudes, ToffoliGate, ToffoliGate_Reference);
AssertOperationsEqualReferenced(3, ToffoliGate, ToffoliGate_Reference);
}


// ------------------------------------------------------
operation T205_FredkinGate_Test () : Unit {
DumpDiff(2, StatePrepMiscAmplitudes, FredkinGate, FredkinGate_Reference);
AssertOperationsEqualReferenced(3, FredkinGate, FredkinGate_Reference);
}

}