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 <mamykhai@microsoft.com>
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 <mamykhai@microsoft.com>
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 <mamykhai@microsoft.com>
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);
     }
 }