diff --git a/katas/content/distinguishing_unitaries/Common.qs b/katas/content/distinguishing_unitaries/Common.qs index 33813df20c..d16b25d49e 100644 --- a/katas/content/distinguishing_unitaries/Common.qs +++ b/katas/content/distinguishing_unitaries/Common.qs @@ -1,4 +1,5 @@ namespace Kata.Verification { + open Microsoft.Quantum.Math; open Microsoft.Quantum.Random; // "Framework" operation for testing tasks for distinguishing unitaries @@ -58,4 +59,32 @@ namespace Kata.Verification { Message("Correct!"); true } + + operation MinusZ (q : Qubit) : Unit is Adj + Ctl { + within { + X(q); + } + apply { + Z(q); + } + } + + operation XZ (q : Qubit) : Unit is Adj + Ctl { + Z(q); + X(q); + } + + operation MinusY (q : Qubit) : Unit is Adj + Ctl { + within { + X(q); + } + apply { + Y(q); + } + } + + operation MinusXZ (q : Qubit) : Unit is Adj + Ctl { + X(q); + Z(q); + } } diff --git a/katas/content/distinguishing_unitaries/h_x/Placeholder.qs b/katas/content/distinguishing_unitaries/h_x/Placeholder.qs index 8d7a9ec725..71aaa3c364 100644 --- a/katas/content/distinguishing_unitaries/h_x/Placeholder.qs +++ b/katas/content/distinguishing_unitaries/h_x/Placeholder.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishHX (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishHfromX(unitary : (Qubit => Unit is Adj + Ctl)) : Int { // Implement your solution here... return -1; diff --git a/katas/content/distinguishing_unitaries/h_x/Solution.qs b/katas/content/distinguishing_unitaries/h_x/Solution.qs index c579366dd8..917a953a41 100644 --- a/katas/content/distinguishing_unitaries/h_x/Solution.qs +++ b/katas/content/distinguishing_unitaries/h_x/Solution.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishHX (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishHfromX(unitary : (Qubit => Unit is Adj + Ctl)) : Int { use q = Qubit(); within { unitary(q); diff --git a/katas/content/distinguishing_unitaries/h_x/Verification.qs b/katas/content/distinguishing_unitaries/h_x/Verification.qs index b57baa044a..6c7ec92b2c 100644 --- a/katas/content/distinguishing_unitaries/h_x/Verification.qs +++ b/katas/content/distinguishing_unitaries/h_x/Verification.qs @@ -3,6 +3,6 @@ namespace Kata.Verification { @EntryPoint() operation CheckSolution() : Bool { - DistinguishUnitaries_Framework([H, X], Kata.DistinguishHX, ["H", "X"], 1) + DistinguishUnitaries_Framework([H, X], Kata.DistinguishHfromX, ["H", "X"], 1) } } diff --git a/katas/content/distinguishing_unitaries/i_x/Placeholder.qs b/katas/content/distinguishing_unitaries/i_x/Placeholder.qs index 24c3749fc0..b4c98ddd4a 100644 --- a/katas/content/distinguishing_unitaries/i_x/Placeholder.qs +++ b/katas/content/distinguishing_unitaries/i_x/Placeholder.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishIX (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishIfromX(unitary : (Qubit => Unit is Adj + Ctl)) : Int { // Implement your solution here... return -1; diff --git a/katas/content/distinguishing_unitaries/i_x/Solution.qs b/katas/content/distinguishing_unitaries/i_x/Solution.qs index e255912819..db76fc3b64 100644 --- a/katas/content/distinguishing_unitaries/i_x/Solution.qs +++ b/katas/content/distinguishing_unitaries/i_x/Solution.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishIX (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishIfromX(unitary : (Qubit => Unit is Adj + Ctl)) : Int { use q = Qubit(); unitary(q); return MResetZ(q) == Zero ? 0 | 1; diff --git a/katas/content/distinguishing_unitaries/i_x/Verification.qs b/katas/content/distinguishing_unitaries/i_x/Verification.qs index 2c5e153cdd..8a2c27828a 100644 --- a/katas/content/distinguishing_unitaries/i_x/Verification.qs +++ b/katas/content/distinguishing_unitaries/i_x/Verification.qs @@ -3,6 +3,6 @@ namespace Kata.Verification { @EntryPoint() operation CheckSolution() : Bool { - DistinguishUnitaries_Framework([I, X], Kata.DistinguishIX, ["I", "X"], 1) + DistinguishUnitaries_Framework([I, X], Kata.DistinguishIfromX, ["I", "X"], 1) } } diff --git a/katas/content/distinguishing_unitaries/i_x_y_z/Placeholder.qs b/katas/content/distinguishing_unitaries/i_x_y_z/Placeholder.qs new file mode 100644 index 0000000000..a10099e05b --- /dev/null +++ b/katas/content/distinguishing_unitaries/i_x_y_z/Placeholder.qs @@ -0,0 +1,7 @@ +namespace Kata { + operation DistinguishPaulis (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + // Implement your solution here... + + return -1; + } +} diff --git a/katas/content/distinguishing_unitaries/i_x_y_z/Solution.qs b/katas/content/distinguishing_unitaries/i_x_y_z/Solution.qs new file mode 100644 index 0000000000..0e8ef3ea20 --- /dev/null +++ b/katas/content/distinguishing_unitaries/i_x_y_z/Solution.qs @@ -0,0 +1,17 @@ +namespace Kata { + operation DistinguishPaulis (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + // apply operation to the 1st qubit of a Bell state and measure in Bell basis + use qs = Qubit[2]; + within { + H(qs[0]); + CNOT(qs[0], qs[1]); + } apply { + unitary(qs[0]); + } + + // after this I -> 00, X -> 01, Y -> 11, Z -> 10 + let ind = MeasureInteger(qs); + let returnValues = [0, 3, 1, 2]; + return returnValues[ind]; + } +} diff --git a/katas/content/distinguishing_unitaries/i_x_y_z/Verification.qs b/katas/content/distinguishing_unitaries/i_x_y_z/Verification.qs new file mode 100644 index 0000000000..5bd6f50dbe --- /dev/null +++ b/katas/content/distinguishing_unitaries/i_x_y_z/Verification.qs @@ -0,0 +1,8 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + + @EntryPoint() + operation CheckSolution() : Bool { + DistinguishUnitaries_Framework([I, X, Y, Z], Kata.DistinguishPaulis, ["I", "X", "Y", "Z"], 1) + } +} diff --git a/katas/content/distinguishing_unitaries/i_x_y_z/index.md b/katas/content/distinguishing_unitaries/i_x_y_z/index.md new file mode 100644 index 0000000000..fc53f791a7 --- /dev/null +++ b/katas/content/distinguishing_unitaries/i_x_y_z/index.md @@ -0,0 +1,11 @@ +**Input:** An operation that implements a single-qubit unitary transformation: +either the identity ($I$ gate) or one of the Pauli gates ($X$, $Y$ or $Z$ gate). + +**Output:** +* 0 if the given operation is the $I$ gate, +* 1 if the given operation is the $X$ gate, +* 2 if the given operation is the $Y$ gate, +* 3 if the given operation is the $Z$ gate. + +The operation will have Adjoint and Controlled variants defined. +You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**. \ No newline at end of file diff --git a/katas/content/distinguishing_unitaries/i_x_y_z/solution.md b/katas/content/distinguishing_unitaries/i_x_y_z/solution.md new file mode 100644 index 0000000000..047f2cd571 --- /dev/null +++ b/katas/content/distinguishing_unitaries/i_x_y_z/solution.md @@ -0,0 +1,11 @@ +This task is quite different from the previous tasks in this section; +at the first glance it might seem impossible to distinguish four different unitaries (i.e., get two bits of information) with just one unitary application! + +However, since the unitaries were chosen carefully (and you're not limited in the number of measurements you can do), it is possible. +The solution uses the Bell states: the four orthogonal states which you can prepare by starting with the first of them $\frac{1}{\sqrt2}(\ket{00} + \ket{11})$ and applying the gates $I$, $X$, $Z$ and $Y$, respectively, to the first qubit. +Thus the solution becomes: prepare the $\frac{1}{\sqrt2}(\ket{00} + \ket{11})$ state, apply the unitary and measure the resulting state in Bell basis to figure out which of the Bell states it is. See the Distinguish Quantum States kata, task 'Distinguish Four Bell states' for the details on how to do that. + +@[solution]({ + "id": "distinguishing_unitaries__i_x_y_z_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/distinguishing_unitaries/i_z/Placeholder.qs b/katas/content/distinguishing_unitaries/i_z/Placeholder.qs index 9e1d382c33..b35050fe57 100644 --- a/katas/content/distinguishing_unitaries/i_z/Placeholder.qs +++ b/katas/content/distinguishing_unitaries/i_z/Placeholder.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishIZ (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishIfromZ(unitary : (Qubit => Unit is Adj + Ctl)) : Int { // Implement your solution here... return -1; diff --git a/katas/content/distinguishing_unitaries/i_z/Solution.qs b/katas/content/distinguishing_unitaries/i_z/Solution.qs index a974b5f9be..70438e5570 100644 --- a/katas/content/distinguishing_unitaries/i_z/Solution.qs +++ b/katas/content/distinguishing_unitaries/i_z/Solution.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishIZ (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishIfromZ(unitary : (Qubit => Unit is Adj + Ctl)) : Int { use q = Qubit(); H(q); unitary(q); diff --git a/katas/content/distinguishing_unitaries/i_z/Verification.qs b/katas/content/distinguishing_unitaries/i_z/Verification.qs index 5fa0ed3594..f54509fd5d 100644 --- a/katas/content/distinguishing_unitaries/i_z/Verification.qs +++ b/katas/content/distinguishing_unitaries/i_z/Verification.qs @@ -3,6 +3,6 @@ namespace Kata.Verification { @EntryPoint() operation CheckSolution() : Bool { - DistinguishUnitaries_Framework([I, Z], Kata.DistinguishIZ, ["I", "Z"], 1) + DistinguishUnitaries_Framework([I, Z], Kata.DistinguishIfromZ, ["I", "Z"], 1) } } diff --git a/katas/content/distinguishing_unitaries/index.md b/katas/content/distinguishing_unitaries/index.md index ff22ddbb9b..3bce8ab1c5 100644 --- a/katas/content/distinguishing_unitaries/index.md +++ b/katas/content/distinguishing_unitaries/index.md @@ -63,6 +63,66 @@ This kata offers you a series of tasks in which you are given one unitary from t ] }) +@[exercise]({ + "id": "distinguishing_unitaries__z_minusz", + "title": "Z or -Z?", + "path": "./z_minusz/", + "qsDependencies": [ + "../KatasLibrary.qs", + "./Common.qs" + ] +}) + +@[exercise]({ + "id": "distinguishing_unitaries__rz_r1", + "title": "Rz or R1?", + "path": "./rz_r1/", + "qsDependencies": [ + "../KatasLibrary.qs", + "./Common.qs" + ] +}) + +@[exercise]({ + "id": "distinguishing_unitaries__y_xz", + "title": "Y or XZ?", + "path": "./y_xz/", + "qsDependencies": [ + "../KatasLibrary.qs", + "./Common.qs" + ] +}) + +@[exercise]({ + "id": "distinguishing_unitaries__y_xz_minusy_minusxz", + "title": "Y or XZ or -Y or -XZ?", + "path": "./y_xz_minusy_minusxz/", + "qsDependencies": [ + "../KatasLibrary.qs", + "./Common.qs" + ] +}) + +@[exercise]({ + "id": "distinguishing_unitaries__i_x_y_z", + "title": "Distinguish Four Pauli Unitaries", + "path": "./i_x_y_z/", + "qsDependencies": [ + "../KatasLibrary.qs", + "./Common.qs" + ] +}) + +@[exercise]({ + "id": "distinguishing_unitaries__rz_ry", + "title": "Rz or Ry?", + "path": "./rz_ry/", + "qsDependencies": [ + "../KatasLibrary.qs", + "./Common.qs" + ] +}) + @[section]({ "id": "distinguishing_unitaries__multi_qubit", "title": "Distinguishing Multi-Qubit Gates" diff --git a/katas/content/distinguishing_unitaries/rz_r1/Placeholder.qs b/katas/content/distinguishing_unitaries/rz_r1/Placeholder.qs new file mode 100644 index 0000000000..1c619d2f6d --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_r1/Placeholder.qs @@ -0,0 +1,9 @@ +namespace Kata { + open Microsoft.Quantum.Math; + + operation DistinguishRzFromR1 (unitary : ((Double, Qubit) => Unit is Adj + Ctl)) : Int { + // Implement your solution here... + + return -1; + } +} diff --git a/katas/content/distinguishing_unitaries/rz_r1/Solution.qs b/katas/content/distinguishing_unitaries/rz_r1/Solution.qs new file mode 100644 index 0000000000..6d35fe4566 --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_r1/Solution.qs @@ -0,0 +1,9 @@ +namespace Kata { + open Microsoft.Quantum.Math; + operation DistinguishRzFromR1 (unitary : ((Double, Qubit) => Unit is Adj+Ctl)) : Int { + use qs = Qubit[2]; + H(qs[0]); + Controlled unitary(qs[0..0], (2.0 * PI(), qs[1])); + return MResetX(qs[0]) == Zero ? 1 | 0; + } +} diff --git a/katas/content/distinguishing_unitaries/rz_r1/Verification.qs b/katas/content/distinguishing_unitaries/rz_r1/Verification.qs new file mode 100644 index 0000000000..df1cf1ebf7 --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_r1/Verification.qs @@ -0,0 +1,8 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + + @EntryPoint() + operation CheckSolution() : Bool { + DistinguishUnitaries_Framework([Rz, R1], Kata.DistinguishRzFromR1, ["Rz", "R1"], 1) + } +} diff --git a/katas/content/distinguishing_unitaries/rz_r1/index.md b/katas/content/distinguishing_unitaries/rz_r1/index.md new file mode 100644 index 0000000000..ca22a39fa7 --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_r1/index.md @@ -0,0 +1,12 @@ +**Input:** An operation that implements a single-qubit unitary transformation: +either the [$R_z$ gate](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/rz) or the [$R1$ gate](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/r1). + +This operation will take two parameters: the first parameter is the rotation angle, in radians, and the second parameter is the qubit to which the gate should be applied (matching normal `Rz` and `R1` gates in Q#). + +> As a reminder, $$R_z(\theta) = \begin{bmatrix} e^{-i\theta/2} & 0 \\ 0 & e^{i\theta/2} \end{bmatrix} \text{, } +R_1(\theta) = \begin{bmatrix} 1 & 0 \\ 0 & e^{i\theta} \end{bmatrix} = e^{i\theta/2} R_z(\theta)$$ + +**Output:** 0 if the given operation is the $R_z$ gate, 1 if the given operation is the $R1$ gate. + +The operation will have Adjoint and Controlled variants defined. +You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**. \ No newline at end of file diff --git a/katas/content/distinguishing_unitaries/rz_r1/solution.md b/katas/content/distinguishing_unitaries/rz_r1/solution.md new file mode 100644 index 0000000000..5efd4932d8 --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_r1/solution.md @@ -0,0 +1,9 @@ +We see that these two gates differ by a global phase $e^{i\theta/2}$. +In this problem we're free to choose the angle parameter which we'll pass to our gate, so we can choose an angle that make this global phase difference something easy to detect: for $\theta = 2\pi$ $e^{i\theta/2} = -1$, so $R_z(\theta) = -I$, and $R_1(\theta) = I$. + +Now we need to distinguish $I$ gate from $-I$ gate, which can be done using controlled variant of the gate in exactly the same way as distinguishing $Z$ gate from $-Z$ gate in the task 'Z or -Z'. + +@[solution]({ + "id": "distinguishing_unitaries__rz_r1_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/distinguishing_unitaries/rz_ry/Placeholder.qs b/katas/content/distinguishing_unitaries/rz_ry/Placeholder.qs new file mode 100644 index 0000000000..003a360c2e --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_ry/Placeholder.qs @@ -0,0 +1,10 @@ +namespace Kata { + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Math; + + operation DistinguishRzFromRy (theta : Double, unitary : (Qubit => Unit is Adj + Ctl)) : Int { + // Implement your solution here... + + return -1; + } +} diff --git a/katas/content/distinguishing_unitaries/rz_ry/Solution.qs b/katas/content/distinguishing_unitaries/rz_ry/Solution.qs new file mode 100644 index 0000000000..7e7e8a2aca --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_ry/Solution.qs @@ -0,0 +1,38 @@ +namespace Kata { + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Math; + + function ComputeRepetitions(angle : Double, offset : Int, accuracy : Double) : Int { + mutable pifactor = 0; + while (true) { + let pimultiple = PI() * IntAsDouble(2 * pifactor + offset); + let times = Round(pimultiple / angle); + if AbsD(pimultiple - (IntAsDouble(times) * angle)) / PI() < accuracy { + return times; + } + set pifactor += 1; + } + return 0; + } + + operation DistinguishRzFromRy (theta : Double, unitary : (Qubit => Unit is Adj+Ctl)) : Int { + use q = Qubit(); + let times = ComputeRepetitions(theta, 1, 0.1); + mutable attempt = 1; + mutable measuredOne = false; + repeat { + for _ in 1 .. times { + unitary(q); + } + // for Rz, we'll never venture away from |0⟩ state, so as soon as we got |1⟩ we know it's not Rz + if MResetZ(q) == One { + set measuredOne = true; + } + // if we try several times and still only get |0⟩s, chances are that it is Rz + } until (attempt == 4 or measuredOne) + fixup { + set attempt += 1; + } + return measuredOne ? 1 | 0; + } +} diff --git a/katas/content/distinguishing_unitaries/rz_ry/Verification.qs b/katas/content/distinguishing_unitaries/rz_ry/Verification.qs new file mode 100644 index 0000000000..82a0964bcd --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_ry/Verification.qs @@ -0,0 +1,14 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + + @EntryPoint() + operation CheckSolution() : Bool { + for theta in [0.04, 0.1, 0.25, 0.31, 0.5, 0.87, 1.05, 1.41, 1.66, 1.75, 2.0, 2.16, 2.22, 2.51, 2.93, 3.0, 3.1] { + Message($"Testing theta = {theta}..."); + if not DistinguishUnitaries_Framework([Rz(theta, _), Ry(theta, _)], Kata.DistinguishRzFromRy(theta, _), ["Rz", "Ry"], -1) { + return false; + } + } + return true; + } +} diff --git a/katas/content/distinguishing_unitaries/rz_ry/index.md b/katas/content/distinguishing_unitaries/rz_ry/index.md new file mode 100644 index 0000000000..2325bac92c --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_ry/index.md @@ -0,0 +1,15 @@ +**Inputs:** + +1. An angle $\theta \in [0.01 \pi; 0.99 \pi]$. +2. An operation that implements a single-qubit unitary transformation: +either the [$R_z(\theta)$ gate](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/rz) or the [$R_y(\theta)$ gate](https://learn.microsoft.com/qsharp/api/qsharp/microsoft.quantum.intrinsic/ry). + +> As a reminder, +> +> $$R_z(\theta) = \begin{bmatrix} e^{-i\theta/2} & 0 \\ 0 & e^{i\theta/2} \end{bmatrix} \\ +R_y(\theta) = \begin{bmatrix} \cos\frac{\theta}{2} & -\sin\frac{\theta}{2} \\ \sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{bmatrix}$$ + +**Output:** 0 if the given operation is the $R_z$ gate, 1 if the given operation is the $R_y$ gate. + +The operation will have Adjoint and Controlled variants defined. +You are allowed to apply the given operation and its adjoint/controlled variants **any number of times**. \ No newline at end of file diff --git a/katas/content/distinguishing_unitaries/rz_ry/solution.md b/katas/content/distinguishing_unitaries/rz_ry/solution.md new file mode 100644 index 0000000000..3140bd17ef --- /dev/null +++ b/katas/content/distinguishing_unitaries/rz_ry/solution.md @@ -0,0 +1,10 @@ +The key observation here is that $R_z$ is a diagonal matrix and $R_y$ is not, so when applied to the $\ket{0}$ state, the former will leave it unchanged (with an extra phase which is not observable), and the latter will convert it to a superposition $\cos\frac{\theta}{2} \ket{0} + \sin\frac{\theta}{2} \ket{1}$. The question is, how to distinguish those two states if they are not orthogonal (and for most values of $\theta$ they will not be)? + +The task description gives you a big hint: it allows you to use the given unitary unlimited number of times, which points to a probabilistic solution (as opposed to deterministic solutions in all previous problems in this kata). Apply the unitary to the $\ket{0}$ state and measure the result; if it is $\ket{1}$, the unitary must be $R_y$, otherwise you can repeat the experiment again. After several iterations of measuring $\ket{0}$ you can conclude that with high probability the unitary is $R_z$. + +To reduce the number of iterations after which you make the decision, you could apply the unitary several times to bring the overall rotation angle closer to $\pi$: in case of $R_y$ gate this would allow you to rotate the state closer to the $\ket{1}$ state, so that you'd detect it with higher probability. + +@[solution]({ + "id": "distinguishing_unitaries__rz_ry_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/distinguishing_unitaries/y_xz/Placeholder.qs b/katas/content/distinguishing_unitaries/y_xz/Placeholder.qs new file mode 100644 index 0000000000..24c576cd2b --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz/Placeholder.qs @@ -0,0 +1,7 @@ +namespace Kata { + operation DistinguishYfromXZ (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + // Implement your solution here... + + return -1; + } +} diff --git a/katas/content/distinguishing_unitaries/y_xz/Solution.qs b/katas/content/distinguishing_unitaries/y_xz/Solution.qs new file mode 100644 index 0000000000..6b4dab334d --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz/Solution.qs @@ -0,0 +1,9 @@ +namespace Kata { + operation DistinguishYfromXZ (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + use qs = Qubit[2]; + H(qs[0]); + Controlled unitary(qs[0..0], qs[1]); + Controlled unitary(qs[0..0], qs[1]); + return MResetX(qs[0]) == Zero ? 0 | 1; + } +} diff --git a/katas/content/distinguishing_unitaries/y_xz/Verification.qs b/katas/content/distinguishing_unitaries/y_xz/Verification.qs new file mode 100644 index 0000000000..69995cfbf5 --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz/Verification.qs @@ -0,0 +1,8 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + + @EntryPoint() + operation CheckSolution() : Bool { + DistinguishUnitaries_Framework([Y, XZ], Kata.DistinguishYfromXZ, ["Y", "XZ"], 1) + } +} diff --git a/katas/content/distinguishing_unitaries/y_xz/index.md b/katas/content/distinguishing_unitaries/y_xz/index.md new file mode 100644 index 0000000000..ae3adc443f --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz/index.md @@ -0,0 +1,7 @@ +**Input:** An operation that implements a single-qubit unitary transformation: +either the $Y$ gate or the sequence of Pauli $Z$ and Pauli $X$ gates (equivalent to applying the $Z$ gate followed by the $X$ gate). + +**Output:** 0 if the given operation is the $Y$ gate, 1 if the given operation is the $XZ$ gate. + +The operation will have Adjoint and Controlled variants defined. +You are allowed to apply the given operation and its adjoint/controlled variants at most **twice**. \ No newline at end of file diff --git a/katas/content/distinguishing_unitaries/y_xz/solution.md b/katas/content/distinguishing_unitaries/y_xz/solution.md new file mode 100644 index 0000000000..1a0954dca7 --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz/solution.md @@ -0,0 +1,10 @@ +> As a reminder, $$Y = \begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix} = iXZ$$ + +We see that these two gates differ by a global phase $i = e^{i\pi}$. Applying the gates twice will give us gates $Y^2 = I$ and $(XZ)^2 = XZXZ = -XXZZ = -I$, respectively. + +Now we need to distinguish $I$ gate from $-I$ gate, which is the same thing we did in the previous task. + +@[solution]({ + "id": "distinguishing_unitaries__y_xz_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Placeholder.qs b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Placeholder.qs new file mode 100644 index 0000000000..9f4f416c7d --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Placeholder.qs @@ -0,0 +1,7 @@ +namespace Kata { + operation DistinguishYfromXZWithPhases (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + // Implement your solution here... + + return -1; + } +} diff --git a/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Solution.qs b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Solution.qs new file mode 100644 index 0000000000..fd4d2d8352 --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Solution.qs @@ -0,0 +1,33 @@ +namespace Kata { + operation DistinguishYfromXZWithPhases (unitary : (Qubit => Unit is Adj+Ctl)) : Int { + use (control, target) = (Qubit(), Qubit()); + // Distinguish Y from iY + within { + H(control); + } apply { + Controlled unitary([control], target); + Controlled unitary([control], target); + } + Reset(target); + let isY = MResetZ(control) == Zero; + + // Distinguish Y from -Y and iY from -iY + within { + H(control); + } apply { + Controlled unitary([control], target); + // apply controlled variant of the gate we're expecting to compensate effect on target qubit + if isY { + CY(control, target); + } else { + CZ(control, target); + CX(control, target); + } + } + let result = isY ? M(control) == Zero ? 0 | 2 + | M(control) == Zero ? 1 | 3; + Reset(control); + return result; + + } +} diff --git a/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Verification.qs b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Verification.qs new file mode 100644 index 0000000000..112e74abdc --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/Verification.qs @@ -0,0 +1,8 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + + @EntryPoint() + operation CheckSolution() : Bool { + DistinguishUnitaries_Framework([Y, MinusXZ, MinusY, XZ], Kata.DistinguishYfromXZWithPhases, ["Y", "-XZ", "-Y", "XZ"], 1) + } +} diff --git a/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/index.md b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/index.md new file mode 100644 index 0000000000..df5d0de067 --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/index.md @@ -0,0 +1,11 @@ +**Input:** An operation that implements a single-qubit unitary transformation: +either the $Y$ gate (possibly with an extra global phase of $-1$) or the sequence of Pauli $Z$ and Pauli $X$ gates (possibly with an extra global phase of $-1$). + +**Output:** +* 0 if the given operation is the $Y$ gate, +* 1 if the given operation is the $-XZ$ gate, +* 2 if the given operation is the $-Y$ gate, +* 3 if the given operation is the $XZ$ gate. + +The operation will have Adjoint and Controlled variants defined. +You are allowed to apply the given operation and its adjoint/controlled variants at most **three times**. \ No newline at end of file diff --git a/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/solution.md b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/solution.md new file mode 100644 index 0000000000..526f64d4fa --- /dev/null +++ b/katas/content/distinguishing_unitaries/y_xz_minusy_minusxz/solution.md @@ -0,0 +1,8 @@ +In this task we have to distinguish 4 gates that were identical up to a global phase, i.e., gates $Y$, $iY$, $-Y$ and $-iY$ (in that order). + +One way to do this is "by hand", similar to the previous tasks. First we'll apply the controlled variant of the unitary twice and check whether the result is $I$ or $-I$ (which allows us to distinguish $\pm Y$ and $\pm iY$, since the first two gates squared will be equivalent to the $I$ gate, and the last two to the $-I$ gate). Then we distinguish the gates in each group ($Y$ from $-Y$ or $iY$ from $-iY$) by applying the controlled variant of the unitary once. + +@[solution]({ + "id": "distinguishing_unitaries__y_xz_minusy_minusxz_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/distinguishing_unitaries/z_minusz/Placeholder.qs b/katas/content/distinguishing_unitaries/z_minusz/Placeholder.qs new file mode 100644 index 0000000000..db32a48f7d --- /dev/null +++ b/katas/content/distinguishing_unitaries/z_minusz/Placeholder.qs @@ -0,0 +1,7 @@ +namespace Kata { + operation DistinguishZfromMinusZ (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + // Implement your solution here... + + return -1; + } +} diff --git a/katas/content/distinguishing_unitaries/z_minusz/Solution.qs b/katas/content/distinguishing_unitaries/z_minusz/Solution.qs new file mode 100644 index 0000000000..5320e4ecf4 --- /dev/null +++ b/katas/content/distinguishing_unitaries/z_minusz/Solution.qs @@ -0,0 +1,8 @@ +namespace Kata { + operation DistinguishZfromMinusZ (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + use qs = Qubit[2]; + H(qs[0]); + Controlled unitary(qs[0..0], qs[1]); + return MResetX(qs[0]) == Zero ? 0 | 1; + } +} diff --git a/katas/content/distinguishing_unitaries/z_minusz/Verification.qs b/katas/content/distinguishing_unitaries/z_minusz/Verification.qs new file mode 100644 index 0000000000..f77037ebf5 --- /dev/null +++ b/katas/content/distinguishing_unitaries/z_minusz/Verification.qs @@ -0,0 +1,8 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + + @EntryPoint() + operation CheckSolution() : Bool { + DistinguishUnitaries_Framework([Z, MinusZ], Kata.DistinguishZfromMinusZ, ["Z", "-Z"], 1) + } +} diff --git a/katas/content/distinguishing_unitaries/z_minusz/index.md b/katas/content/distinguishing_unitaries/z_minusz/index.md new file mode 100644 index 0000000000..2a28ca479d --- /dev/null +++ b/katas/content/distinguishing_unitaries/z_minusz/index.md @@ -0,0 +1,7 @@ +**Input:** An operation that implements a single-qubit unitary transformation: +either the $Z$ gate or the minus $Z$ gate (i.e., the gate $-\ket{0}\bra{0} + \ket{1}\bra{1}$). + +**Output:** 0 if the given operation is the $Z$ gate, 1 if the given operation is the $-Z$ gate. + +The operation will have Adjoint and Controlled variants defined. +You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**. \ No newline at end of file diff --git a/katas/content/distinguishing_unitaries/z_minusz/solution.md b/katas/content/distinguishing_unitaries/z_minusz/solution.md new file mode 100644 index 0000000000..921209d881 --- /dev/null +++ b/katas/content/distinguishing_unitaries/z_minusz/solution.md @@ -0,0 +1,47 @@ +This task is more interesting: the given gates differ by a global phase they introduce (i.e., each of them is a multiple of the other), and the results of applying them to any single-qubit state are going to be indistinguishable by any measurement you can devise. + +Fortunately, we are given not just the unitary itself, but also its controlled variant, i.e., the gate which applies the given unitary if the control qubit is in the $\ket{1}$ state and does nothing if it is in the $\ket{0}$ state. +This allows us to use so called "phase kickback" trick, in which applying a controlled version of a gate allows us to observe the phase introduced by this gate on the control qubit. Indeed, + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StateControlled ZControlled $-Z$
$\ket{00}$$\ket{00}$$\ket{00}$
$\ket{01}$$\ket{01}$$\ket{01}$
$\ket{10}$$\color{blue}{\ket{10}}$$\color{blue}{-\ket{10}}$
$\ket{11}$$\color{blue}{-\ket{11}}$$\color{blue}{\ket{11}}$
+ +We see that both controlled gates don't modify the states with the control qubit in the $\ket{0}$ state, but if the control qubit is in the $\ket{1}$ state, they introduce a $-1$ phase to different basis states. +We can take advantage of this if we apply the controlled gate to a state in which the *control qubit* is in superposition, such as $\frac{1}{\sqrt2}(\ket{0} + \ket{1}) \otimes \ket{0}$: + +$$\text{Controlled Z}\frac{1}{\sqrt2}(\ket{0} + \ket{1}) \otimes \ket{0} = \frac{1}{\sqrt2}(\ket{0} + \ket{1}) \otimes \ket{0}$$ +$$\text{Controlled }-\text{Z}\frac{1}{\sqrt2}(\ket{0} + \ket{1}) \otimes \ket{0} = \frac{1}{\sqrt2}(\ket{0} - \ket{1}) \otimes \ket{0}$$ + +After this we can measure the first qubit to distinguish $\frac{1}{\sqrt2}(\ket{0} + \ket{1})$ from $\frac{1}{\sqrt2}(\ket{0} - \ket{1})$, like we did in task 'Identity or Z'. + +> In Q# we can express controlled version of a gate using [Controlled functor](https://learn.microsoft.com/en-us/azure/quantum/user-guide/language/expressions/functorapplication#controlled-functor): the first argument of the resulting gate will be an array of control qubits, and the second one - the arguments of the original gate (in this case just the target qubit). + +@[solution]({ + "id": "distinguishing_unitaries__z_minusz_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/distinguishing_unitaries/z_s/Placeholder.qs b/katas/content/distinguishing_unitaries/z_s/Placeholder.qs index b15bec36a9..516dca31b9 100644 --- a/katas/content/distinguishing_unitaries/z_s/Placeholder.qs +++ b/katas/content/distinguishing_unitaries/z_s/Placeholder.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishZS (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishZfromS(unitary : (Qubit => Unit is Adj + Ctl)) : Int { // Implement your solution here... return -1; diff --git a/katas/content/distinguishing_unitaries/z_s/Solution.qs b/katas/content/distinguishing_unitaries/z_s/Solution.qs index a1a08491c0..81c0b0ce55 100644 --- a/katas/content/distinguishing_unitaries/z_s/Solution.qs +++ b/katas/content/distinguishing_unitaries/z_s/Solution.qs @@ -1,5 +1,5 @@ namespace Kata { - operation DistinguishZS (unitary : (Qubit => Unit is Adj + Ctl)) : Int { + operation DistinguishZfromS(unitary : (Qubit => Unit is Adj + Ctl)) : Int { use q = Qubit(); H(q); unitary(q); diff --git a/katas/content/distinguishing_unitaries/z_s/Verification.qs b/katas/content/distinguishing_unitaries/z_s/Verification.qs index be77968d3d..6b92b48578 100644 --- a/katas/content/distinguishing_unitaries/z_s/Verification.qs +++ b/katas/content/distinguishing_unitaries/z_s/Verification.qs @@ -3,6 +3,6 @@ namespace Kata.Verification { @EntryPoint() operation CheckSolution() : Bool { - DistinguishUnitaries_Framework([Z, S], Kata.DistinguishZS, ["Z", "S"], 1) + DistinguishUnitaries_Framework([Z, S], Kata.DistinguishZfromS, ["Z", "S"], 1) } }