From 43163107d36f93617b21335f4e2e8e9c57bc9bb3 Mon Sep 17 00:00:00 2001 From: Vincent van Wingerden <25651976+vivanwin@users.noreply.github.com> Date: Sat, 14 Mar 2020 21:24:20 +0100 Subject: [PATCH 1/4] update tests for basic gates --- BasicGates/Tests.qs | 175 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 167 insertions(+), 8 deletions(-) diff --git a/BasicGates/Tests.qs b/BasicGates/Tests.qs index 5a6ee84ae6c..2c9cc5a8760 100644 --- a/BasicGates/Tests.qs +++ b/BasicGates/Tests.qs @@ -32,28 +32,92 @@ namespace Quantum.Kata.BasicGates { operation ArrayWrapperOperation (op : (Qubit => Unit is Adj+Ctl), qs : Qubit[]) : Unit is Adj+Ctl { Controlled op([qs[0]], qs[1]); } - + + operation DumpDiffOnOneInput ( testImpl : (Qubit => Unit is Adj+Ctl), + refImpl : (Qubit => Unit is Adj+Ctl)) : Unit { + using(q = Qubit()){ + + //Prep a nice state + let state = ArcCos(0.6); + StatePrep_A(state,q); + Message("Start state:"); + DumpMachine(()); + + //Implement the reference solution and show result + Message("The desired state:"); + refImpl(q); + DumpMachine(()); + //Reset for test implementation + Reset(q); + + //Prep the state again for test implementation + StatePrep_A(state,q); + //Implement test implementation and test dump the result + testImpl(q); + Message("The actual state:"); + DumpMachine(()); + + Reset(q); + } + } + + operation DumpDiffOnOneInputControlled ( testImpl : (Qubit => Unit is Adj+Ctl), + refImpl : (Qubit => Unit is Adj+Ctl)) : Unit { + using(qs = Qubit[2]){ + + H(qs[0]); + //Prep a nice state + let state = ArcCos(0.6); + StatePrep_A(state,qs[1]); + Message("Start state:"); + DumpMachine(()); + + + //Implement the reference solution and show result + Message("The desired state:"); + Controlled refImpl([qs[0]],qs[1]); + DumpMachine(()); + //Reset for test implementation + ResetAll(qs); + + H(qs[0]); + //Prep the state again for test implementation + StatePrep_A(state,qs[1]); + //Implement test implementation and test dump the result + Controlled testImpl([qs[0]],qs[1]); + Message("The actual state:"); + DumpMachine(()); + + ResetAll(qs); + } + } // ------------------------------------------------------ operation T101_StateFlip_Test () : Unit { + DumpDiffOnOneInput(StateFlip,StateFlip_Reference); AssertOperationsEqualReferenced(2, ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _)); } // ------------------------------------------------------ operation T102_BasisChange_Test () : Unit { + DumpDiffOnOneInput(BasisChange,BasisChange_Reference); AssertOperationsEqualReferenced(2, ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _)); } // ------------------------------------------------------ operation T103_SignFlip_Test () : Unit { + DumpDiffOnOneInput(SignFlip,SignFlip_Reference); AssertOperationsEqualReferenced(2, ArrayWrapperOperation(SignFlip, _), ArrayWrapperOperation(SignFlip_Reference, _)); } // ------------------------------------------------------ operation T104_AmplitudeChange_Test () : Unit { + let dumpAlpha = ((2.0 * PI()) * IntAsDouble(6)) / 36.0; + DumpDiffOnOneInput(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, _), _)); @@ -63,12 +127,16 @@ namespace Quantum.Kata.BasicGates { // ------------------------------------------------------ operation T105_PhaseFlip_Test () : Unit { + DumpDiffOnOneInput(PhaseFlip,PhaseFlip_Reference); AssertOperationsEqualReferenced(2, ArrayWrapperOperation(PhaseFlip, _), ArrayWrapperOperation(PhaseFlip_Reference, _)); } // ------------------------------------------------------ operation T106_PhaseChange_Test () : Unit { + let dumpAlpha = ((2.0 * PI()) * IntAsDouble(10)) / 36.0; + DumpDiffOnOneInput(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, _), _)); @@ -78,6 +146,8 @@ namespace Quantum.Kata.BasicGates { // ------------------------------------------------------ operation T107_GlobalPhaseChange_Test () : Unit { + + DumpDiffOnOneInputControlled(GlobalPhaseChange,GlobalPhaseChange_Reference); AssertOperationsEqualReferenced(2, ArrayWrapperOperation(GlobalPhaseChange, _), ArrayWrapperOperation(GlobalPhaseChange_Reference, _)); } @@ -126,22 +196,78 @@ namespace Quantum.Kata.BasicGates { } } - + operation DumpDiffBellStates ( testImpl : (Qubit[] => Unit is Adj), + refImpl : (Qubit[] => Unit is Adj), + startState : Int) : Unit{ + using(qs = Qubit[2]){ + //Prep the bell state and dump this start state + StatePrep_BellState(qs, startState); + Message("Start state:"); + DumpMachine(()); + + //Implement and dump the reference state + refImpl(qs); + Message("Desired state:"); + DumpMachine(()); + ResetAll(qs); + + //Implement and dump the task state + StatePrep_BellState(qs,startState); + testImpl(qs); + Message("The actual state:"); + DumpMachine(()); + + ResetAll(qs); + } + } + + operation DumpDiffBellStatesControlled (testImpl : (Qubit[] => Unit is Adj), + refImpl : (Qubit[] => Unit is Adj), + startState : Int) : Unit{ + using(qs = Qubit[3]){ + + H(qs[0]); + //Prep the bell state and dump this start state + StatePrep_BellState(Rest(qs), startState); + Message("Start state:"); + DumpMachine(()); + + //Implement and dump the reference state + refImpl(Rest(qs)); + Message("Desired state:"); + DumpMachine(()); + ResetAll(qs); + + H(qs[0]); + //Implement and dump the task state + StatePrep_BellState(Rest(qs),startState); + testImpl(Rest(qs)); + Message("The actual state:"); + DumpMachine(()); + + ResetAll(qs); + } + } + + // ------------------------------------------------------ operation T108_BellStateChange1_Test () : Unit { + DumpDiffBellStates(BellStateChange1,BellStateChange1_Reference,0); VerifyBellStateConversion(BellStateChange1, 0, 1); } // ------------------------------------------------------ operation T109_BellStateChange2_Test () : Unit { + DumpDiffBellStates(BellStateChange2,BellStateChange2_Reference,0); VerifyBellStateConversion(BellStateChange2, 0, 2); } // ------------------------------------------------------ operation T110_BellStateChange3_Test () : Unit { + DumpDiffBellStatesControlled(BellStateChange3,BellStateChange3_Reference,0); VerifyBellStateConversion(BellStateChange3, 0, 3); } @@ -149,13 +275,45 @@ namespace Quantum.Kata.BasicGates { // ------------------------------------------------------ // prepare state |A⟩ = cos(α) * |0⟩ + sin(α) * |1⟩ operation StatePrep_A (alpha : Double, q : Qubit) : Unit is Adj { - Ry(2.0 * alpha, q); + Ry(2.0 * alpha, q); + } + //Prepare a state for the various dumps + operation StatePrep_B (qs : Qubit[]) : Unit is Adj { + let alphas = [5.0,10.0,15.0]; + for(index in 0 .. Length(qs) - 1){ + Ry((2.0 * alphas[index]) + IntAsDouble(index + 1) * 2.0 , qs[index]); + Rz(2.0 * alphas[index], qs[index]); + } } - + operation DumpDiffOnMultiInput (N : Int, + testImpl : (Qubit[] => Unit is Adj), + refImpl : (Qubit[] => Unit is Adj), + stateprep : (Qubit[] => Unit is Adj )) : Unit { + + using(qs = Qubit[N]){ + stateprep(qs); + Message("Start state:"); + DumpMachine(()); + //Display the proper solution + refImpl(qs); + Message("The desired state:"); + DumpMachine(); + ResetAll(qs); + + //Display the test implementation + stateprep(qs); + testImpl(qs); + Message("The actual state:"); + DumpMachine(); + ResetAll(qs); + } + } + // ------------------------------------------------------ operation T201_TwoQubitGate1_Test () : Unit { - + DumpDiffOnMultiInput(2,TwoQubitGate1,TwoQubitGate1_Reference,StatePrep_B); + // 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]) { @@ -163,7 +321,6 @@ namespace Quantum.Kata.BasicGates { let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0; within { - // prepare A state StatePrep_A(alpha, qs[0]); } apply { @@ -187,9 +344,9 @@ namespace Quantum.Kata.BasicGates { ApplyToEachA(H, qs); } - // ------------------------------------------------------ operation T202_TwoQubitGate2_Test () : Unit { + DumpDiffOnMultiInput(2,TwoQubitGate2,TwoQubitGate2_Reference,StatePrep_PlusPlus); using (qs = Qubit[2]) { // prepare |+⟩ ⊗ |+⟩ state StatePrep_PlusPlus(qs); @@ -214,6 +371,7 @@ namespace Quantum.Kata.BasicGates { operation T203_TwoQubitGate3_Test () : Unit { + DumpDiffOnMultiInput(2,TwoQubitGate3,TwoQubitGate3_Reference,StatePrep_B); AssertOperationsEqualReferenced(2, SwapWrapper, TwoQubitGate3_Reference); AssertOperationsEqualReferenced(2, TwoQubitGate3, TwoQubitGate3_Reference); } @@ -221,13 +379,14 @@ namespace Quantum.Kata.BasicGates { // ------------------------------------------------------ operation T204_ToffoliGate_Test () : Unit { + DumpDiffOnMultiInput(3,ToffoliGate, ToffoliGate_Reference, StatePrep_B); AssertOperationsEqualReferenced(3, ToffoliGate, ToffoliGate_Reference); } // ------------------------------------------------------ operation T205_FredkinGate_Test () : Unit { + DumpDiffOnMultiInput(3,FredkinGate, FredkinGate_Reference, StatePrep_B); AssertOperationsEqualReferenced(3, FredkinGate, FredkinGate_Reference); } - } From b2c00d210bd068c23c494d17d6f49db788034362 Mon Sep 17 00:00:00 2001 From: Mariia Mykhailova Date: Wed, 18 Mar 2020 22:32:00 -0700 Subject: [PATCH 2/4] A round of cleanup: * Unify various DumpDiffs into one, more parametrized method * Clean up presentation of several tasks, add (hopefully) helpful messages --- BasicGates/ReferenceImplementation.qs | 10 +- BasicGates/Tasks.qs | 10 +- BasicGates/Tests.qs | 289 ++++++++++---------------- 3 files changed, 118 insertions(+), 191 deletions(-) diff --git a/BasicGates/ReferenceImplementation.qs b/BasicGates/ReferenceImplementation.qs index a43fa6b0922..fec42578c80 100644 --- a/BasicGates/ReferenceImplementation.qs +++ b/BasicGates/ReferenceImplementation.qs @@ -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]); } @@ -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]); } @@ -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]); @@ -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]); } @@ -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])); } diff --git a/BasicGates/Tasks.qs b/BasicGates/Tasks.qs index da426062e2c..494de48e8a9 100644 --- a/BasicGates/Tasks.qs +++ b/BasicGates/Tasks.qs @@ -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 { // ... } @@ -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 { // ... } @@ -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. @@ -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 { // ... } @@ -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 { // ... } diff --git a/BasicGates/Tests.qs b/BasicGates/Tests.qs index 2c9cc5a8760..d965ee44a33 100644 --- a/BasicGates/Tests.qs +++ b/BasicGates/Tests.qs @@ -26,129 +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]); } - operation DumpDiffOnOneInput ( testImpl : (Qubit => Unit is Adj+Ctl), - refImpl : (Qubit => Unit is Adj+Ctl)) : Unit { - using(q = Qubit()){ - - //Prep a nice state - let state = ArcCos(0.6); - StatePrep_A(state,q); - Message("Start state:"); - DumpMachine(()); - //Implement the reference solution and show result + // ------------------------------------------------------ + // 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:"); - refImpl(q); - DumpMachine(()); - //Reset for test implementation - Reset(q); + DumpMachine(); + ResetAll(qs); - //Prep the state again for test implementation - StatePrep_A(state,q); - //Implement test implementation and test dump the result - testImpl(q); + // Prepare the input state again for test implementation + statePrep(qs); + // Apply learner's solution and show result + testImpl(qs); Message("The actual state:"); - DumpMachine(()); + DumpMachine(); + ResetAll(qs); + } + } - Reset(q); - } - } - operation DumpDiffOnOneInputControlled ( testImpl : (Qubit => Unit is Adj+Ctl), - refImpl : (Qubit => Unit is Adj+Ctl)) : Unit { - using(qs = Qubit[2]){ - - H(qs[0]); - //Prep a nice state - let state = ArcCos(0.6); - StatePrep_A(state,qs[1]); - Message("Start state:"); - DumpMachine(()); + // 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, _)); + } - - //Implement the reference solution and show result - Message("The desired state:"); - Controlled refImpl([qs[0]],qs[1]); - DumpMachine(()); - //Reset for test implementation - ResetAll(qs); - H(qs[0]); - //Prep the state again for test implementation - StatePrep_A(state,qs[1]); - //Implement test implementation and test dump the result - Controlled testImpl([qs[0]],qs[1]); - Message("The actual state:"); - DumpMachine(()); - - ResetAll(qs); - } - } - // ------------------------------------------------------ operation T101_StateFlip_Test () : Unit { - DumpDiffOnOneInput(StateFlip,StateFlip_Reference); - AssertOperationsEqualReferenced(2, ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _)); + DumpDiffOnOneQubit(StateFlip, StateFlip_Reference); + AssertOperationsEqualReferenced(2, ArrayWrapperControlled(StateFlip, _), + ArrayWrapperControlled(StateFlip_Reference, _)); } // ------------------------------------------------------ operation T102_BasisChange_Test () : Unit { - DumpDiffOnOneInput(BasisChange,BasisChange_Reference); - AssertOperationsEqualReferenced(2, ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _)); + DumpDiffOnOneQubit(BasisChange, BasisChange_Reference); + AssertOperationsEqualReferenced(2, ArrayWrapperControlled(BasisChange, _), + ArrayWrapperControlled(BasisChange_Reference, _)); } // ------------------------------------------------------ operation T103_SignFlip_Test () : Unit { - DumpDiffOnOneInput(SignFlip,SignFlip_Reference); - 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; - DumpDiffOnOneInput(AmplitudeChange(dumpAlpha, _),AmplitudeChange_Reference(dumpAlpha, _)); + 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 { - DumpDiffOnOneInput(PhaseFlip,PhaseFlip_Reference); - 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; - DumpDiffOnOneInput(PhaseChange(dumpAlpha,_),PhaseChange_Reference(dumpAlpha,_)); + 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, _), _)); } } // ------------------------------------------------------ - operation T107_GlobalPhaseChange_Test () : Unit { + // 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]); + } - DumpDiffOnOneInputControlled(GlobalPhaseChange,GlobalPhaseChange_Reference); - AssertOperationsEqualReferenced(2, ArrayWrapperOperation(GlobalPhaseChange, _), ArrayWrapperOperation(GlobalPhaseChange_Reference, _)); + operation T107_GlobalPhaseChange_Test () : Unit { + // 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, _)); } @@ -196,132 +204,46 @@ namespace Quantum.Kata.BasicGates { } } - operation DumpDiffBellStates ( testImpl : (Qubit[] => Unit is Adj), - refImpl : (Qubit[] => Unit is Adj), - startState : Int) : Unit{ - using(qs = Qubit[2]){ - - //Prep the bell state and dump this start state - StatePrep_BellState(qs, startState); - Message("Start state:"); - DumpMachine(()); - - //Implement and dump the reference state - refImpl(qs); - Message("Desired state:"); - DumpMachine(()); - ResetAll(qs); - - //Implement and dump the task state - StatePrep_BellState(qs,startState); - testImpl(qs); - Message("The actual state:"); - DumpMachine(()); - - ResetAll(qs); - } - } - - operation DumpDiffBellStatesControlled (testImpl : (Qubit[] => Unit is Adj), - refImpl : (Qubit[] => Unit is Adj), - startState : Int) : Unit{ - using(qs = Qubit[3]){ - - H(qs[0]); - //Prep the bell state and dump this start state - StatePrep_BellState(Rest(qs), startState); - Message("Start state:"); - DumpMachine(()); - - //Implement and dump the reference state - refImpl(Rest(qs)); - Message("Desired state:"); - DumpMachine(()); - ResetAll(qs); - - H(qs[0]); - //Implement and dump the task state - StatePrep_BellState(Rest(qs),startState); - testImpl(Rest(qs)); - Message("The actual state:"); - DumpMachine(()); - ResetAll(qs); - } - } - - // ------------------------------------------------------ operation T108_BellStateChange1_Test () : Unit { - DumpDiffBellStates(BellStateChange1,BellStateChange1_Reference,0); + DumpDiff(2, StatePrep_BellState(_, 0), BellStateChange1, BellStateChange1_Reference); VerifyBellStateConversion(BellStateChange1, 0, 1); } // ------------------------------------------------------ operation T109_BellStateChange2_Test () : Unit { - DumpDiffBellStates(BellStateChange2,BellStateChange2_Reference,0); + DumpDiff(2, StatePrep_BellState(_, 0), BellStateChange2, BellStateChange2_Reference); VerifyBellStateConversion(BellStateChange2, 0, 2); } // ------------------------------------------------------ operation T110_BellStateChange3_Test () : Unit { - DumpDiffBellStatesControlled(BellStateChange3,BellStateChange3_Reference,0); + 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)); } - //Prepare a state for the various dumps - operation StatePrep_B (qs : Qubit[]) : Unit is Adj { - let alphas = [5.0,10.0,15.0]; - for(index in 0 .. Length(qs) - 1){ - Ry((2.0 * alphas[index]) + IntAsDouble(index + 1) * 2.0 , qs[index]); - Rz(2.0 * alphas[index], qs[index]); - } - } - - operation DumpDiffOnMultiInput (N : Int, - testImpl : (Qubit[] => Unit is Adj), - refImpl : (Qubit[] => Unit is Adj), - stateprep : (Qubit[] => Unit is Adj )) : Unit { - - using(qs = Qubit[N]){ - stateprep(qs); - Message("Start state:"); - DumpMachine(()); - //Display the proper solution - refImpl(qs); - Message("The desired state:"); - DumpMachine(); - ResetAll(qs); - //Display the test implementation - stateprep(qs); - testImpl(qs); - Message("The actual state:"); - DumpMachine(); - ResetAll(qs); - } - } - - // ------------------------------------------------------ operation T201_TwoQubitGate1_Test () : Unit { - DumpDiffOnMultiInput(2,TwoQubitGate1,TwoQubitGate1_Reference,StatePrep_B); + 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 { - 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 @@ -338,25 +260,20 @@ 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 { - DumpDiffOnMultiInput(2,TwoQubitGate2,TwoQubitGate2_Reference,StatePrep_PlusPlus); + DumpDiff(2, ApplyToEachCA(H, _), TwoQubitGate2, TwoQubitGate2_Reference); using (qs = Qubit[2]) { - // prepare |+⟩ ⊗ |+⟩ state - StatePrep_PlusPlus(qs); + within { + // prepare |+⟩ ⊗ |+⟩ state + ApplyToEachCA(H, qs); + } apply { + // apply operation that needs to be tested + TwoQubitGate2(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); + // apply adjoint reference operation + Adjoint TwoQubitGate2_Reference(qs); + } // assert that all qubits end up in |0⟩ state AssertAllZero(qs); @@ -364,6 +281,16 @@ namespace Quantum.Kata.BasicGates { } + // ------------------------------------------------------ + // 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]); @@ -371,7 +298,7 @@ namespace Quantum.Kata.BasicGates { operation T203_TwoQubitGate3_Test () : Unit { - DumpDiffOnMultiInput(2,TwoQubitGate3,TwoQubitGate3_Reference,StatePrep_B); + DumpDiff(2, StatePrepMiscAmplitudes, TwoQubitGate3, TwoQubitGate3_Reference); AssertOperationsEqualReferenced(2, SwapWrapper, TwoQubitGate3_Reference); AssertOperationsEqualReferenced(2, TwoQubitGate3, TwoQubitGate3_Reference); } @@ -379,14 +306,14 @@ namespace Quantum.Kata.BasicGates { // ------------------------------------------------------ operation T204_ToffoliGate_Test () : Unit { - DumpDiffOnMultiInput(3,ToffoliGate, ToffoliGate_Reference, StatePrep_B); + DumpDiff(2, StatePrepMiscAmplitudes, ToffoliGate, ToffoliGate_Reference); AssertOperationsEqualReferenced(3, ToffoliGate, ToffoliGate_Reference); } // ------------------------------------------------------ operation T205_FredkinGate_Test () : Unit { - DumpDiffOnMultiInput(3,FredkinGate, FredkinGate_Reference, StatePrep_B); + DumpDiff(2, StatePrepMiscAmplitudes, FredkinGate, FredkinGate_Reference); AssertOperationsEqualReferenced(3, FredkinGate, FredkinGate_Reference); } } From 6330a813f65bf87b222656b13fb6cadf320209fd Mon Sep 17 00:00:00 2001 From: Mariia Mykhailova Date: Wed, 18 Mar 2020 22:58:59 -0700 Subject: [PATCH 3/4] Add "+Ctl" to Notebook version as well --- BasicGates/BasicGates.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/BasicGates/BasicGates.ipynb b/BasicGates/BasicGates.ipynb index 0542f050c44..ae7c7a6db0d 100644 --- a/BasicGates/BasicGates.ipynb +++ b/BasicGates/BasicGates.ipynb @@ -396,7 +396,7 @@ "source": [ "%kata T201_TwoQubitGate1_Test\n", "\n", - "operation TwoQubitGate1 (qs : Qubit[]) : Unit is Adj {\n", + "operation TwoQubitGate1 (qs : Qubit[]) : Unit is Adj+Ctl {\n", " // ...\n", "}" ] @@ -424,7 +424,7 @@ "source": [ "%kata T202_TwoQubitGate2_Test\n", "\n", - "operation TwoQubitGate2 (qs : Qubit[]) : Unit is Adj {\n", + "operation TwoQubitGate2 (qs : Qubit[]) : Unit is Adj+Ctl {\n", " // ...\n", "}" ] @@ -451,7 +451,7 @@ "source": [ "%kata T203_TwoQubitGate3_Test\n", "\n", - "operation TwoQubitGate3 (qs : Qubit[]) : Unit is Adj {\n", + "operation TwoQubitGate3 (qs : Qubit[]) : Unit is Adj+Ctl {\n", " // ...\n", "}" ] @@ -476,7 +476,7 @@ "source": [ "%kata T204_ToffoliGate_Test\n", "\n", - "operation ToffoliGate (qs : Qubit[]) : Unit is Adj {\n", + "operation ToffoliGate (qs : Qubit[]) : Unit is Adj+Ctl {\n", " // ...\n", "}" ] @@ -501,7 +501,7 @@ "source": [ "%kata T205_FredkinGate_Test\n", "\n", - "operation FredkinGate (qs : Qubit[]) : Unit is Adj {\n", + "operation FredkinGate (qs : Qubit[]) : Unit is Adj+Ctl {\n", " // ...\n", "}" ] From 7a7cb920187b606e62688644d4b68798f65ce98a Mon Sep 17 00:00:00 2001 From: Mariia Mykhailova Date: Wed, 18 Mar 2020 23:16:17 -0700 Subject: [PATCH 4/4] Fix number of qubits for Toffoli and Fredkin --- BasicGates/Tests.qs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BasicGates/Tests.qs b/BasicGates/Tests.qs index d965ee44a33..982643e6a38 100644 --- a/BasicGates/Tests.qs +++ b/BasicGates/Tests.qs @@ -306,14 +306,14 @@ namespace Quantum.Kata.BasicGates { // ------------------------------------------------------ operation T204_ToffoliGate_Test () : Unit { - DumpDiff(2, StatePrepMiscAmplitudes, ToffoliGate, ToffoliGate_Reference); + DumpDiff(3, StatePrepMiscAmplitudes, ToffoliGate, ToffoliGate_Reference); AssertOperationsEqualReferenced(3, ToffoliGate, ToffoliGate_Reference); } // ------------------------------------------------------ operation T205_FredkinGate_Test () : Unit { - DumpDiff(2, StatePrepMiscAmplitudes, FredkinGate, FredkinGate_Reference); + DumpDiff(3, StatePrepMiscAmplitudes, FredkinGate, FredkinGate_Reference); AssertOperationsEqualReferenced(3, FredkinGate, FredkinGate_Reference); } }