Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Measurements tasks 2.2-2.3 to Distinguishing States #1615

Merged
merged 3 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 0 additions & 40 deletions katas/content/distinguishing_states/Common.qs

This file was deleted.

21 changes: 19 additions & 2 deletions katas/content/distinguishing_states/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,25 @@ This kata is designed to get you familiar with the concept of measurements and u
"title": "|0〉 or |+〉?",
"path": "./zero_plus/",
"qsDependencies": [
"../KatasLibrary.qs",
"./Common.qs"
"../KatasLibrary.qs"
]
})

@[exercise]({
"id": "distinguishing_states__zero_plus_inc",
"title": "|0〉, |+〉 or Inconclusive?",
"path": "./zero_plus_inc/",
"qsDependencies": [
"../KatasLibrary.qs"
]
})

@[exercise]({
"id": "distinguishing_states__peres_wooters_game",
"title": "Peres/Wooters game",
"path": "./peres_wooters_game/",
"qsDependencies": [
"../KatasLibrary.qs"
]
})

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Kata {
operation IsQubitNotInABC(q : Qubit) : Int {
// Implement your solution here...
return -1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Kata {
open Microsoft.Quantum.Math;
operation IsQubitNotInABC (q : Qubit) : Int {
let alpha = ArcCos(Sqrt(2.0 / 3.0));

use a = Qubit();
Z(q);
CNOT(a, q);
Controlled H([q], a);
S(a);
X(q);

ApplyControlledOnInt(0, Ry, [a], (-2.0 * alpha, q));
CNOT(a, q);
Controlled H([q], a);
CNOT(a, q);

let res0 = MResetZ(a);
let res1 = M(q);

if (res0 == Zero and res1 == Zero) {
return 0;
}
elif (res0 == One and res1 == Zero) {
return 1;
}
elif (res0 == Zero and res1 == One) {
return 2;
}
else {
// this should never occur
return 3;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
namespace Kata.Verification {
open Microsoft.Quantum.Katas;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Random;
open Microsoft.Quantum.Math;

operation StatePrep_IsQubitNotInABC (q : Qubit, state : Int) : Unit {
let alpha = (2.0 * PI()) / 3.0;
H(q);

if state == 0 {
// convert |0⟩ to 1/sqrt(2) (|0⟩ + |1⟩)
}
elif state == 1 {
// convert |0⟩ to 1/sqrt(2) (|0⟩ + ω |1⟩), where ω = exp(2iπ/3)
R1(alpha, q);
}
else {
// convert |0⟩ to 1/sqrt(2) (|0⟩ + ω² |1⟩), where ω = exp(2iπ/3)
R1(2.0 * alpha, q);
}
}


@EntryPoint()
operation CheckSolution () : Bool {
let nTotal = 1000;
mutable bad_value = 0;
mutable wrong_state = 0;

use qs = Qubit[1];

for i in 1 .. nTotal {
// get a random integer to define the state of the qubits
let state = DrawRandomInt(0, 2);

// do state prep: convert |0⟩ to outcome with return equal to state
StatePrep_IsQubitNotInABC(qs[0], state);

// get the solution's answer and verify that it's a match
let ans = Kata.IsQubitNotInABC(qs[0]);

// check that the value of ans is 0, 1 or 2
if (ans < 0 or ans > 2) {
set bad_value += 1;
}

// check if upon conclusive result the answer is actually correct
if ans == state {
set wrong_state += 1;
}

// we're not checking the state of the qubit after the operation
ResetAll(qs);
}

if bad_value == 0 and wrong_state == 0 {
Message("Correct!");
return true;
} else {
if bad_value > 0 {
Message($"Solution returned values other than 0, 1 or 2 {bad_value} times.");
}
if wrong_state > 0 {
Message($"Solution gave incorrect response {wrong_state} times");
}
Message("Incorrect.");
return false;
}
}
}
17 changes: 17 additions & 0 deletions katas/content/distinguishing_states/peres_wooters_game/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
**Input:** A qubit which is guaranteed to be in one of the three states:

* $\ket{A} = \frac{1}{\sqrt{2}} \big( \ket{0} + \ket{1} \big)$,
* $\ket{B} = \frac{1}{\sqrt{2}} \big( \ket{0} + \omega \ket{1} \big)$,
* $\ket{C}= \frac{1}{\sqrt{2}} \big( \ket{0} + \omega^2 \ket{1} \big)$,

Here $\omega = e^{2i \pi/ 3}$.

**Output:**

* 1 or 2 if the qubit was in the $\ket{A}$ state,
* 0 or 2 if the qubit was in the $\ket{B}$ state,
* 0 or 1 if the qubit was in the $\ket{C}$ state.

You are never allowed to give an incorrect answer. Your solution will be called multiple times, with one of the states picked with equal probability every time.

The state of the qubit at the end of the operation does not matter.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
> The task is a game inspired by a quantum detection problem due to Holevo ("Information-theoretical aspects of quantum measurement", A. Holevo) and Peres/Wootters ("Optimal detection of quantum information", A. Peres and W. K. Wootters). In the game, player A thinks of a number (0, 1 or 2) and the opponent, player B, tries to guess any number but the one chosen by player A.
>
> Classically, if you just made a guess, you'd have to ask two questions to be right $100\%$ of the time. If instead, player A prepares a qubit with 0, 1, or 2 encoded into three single qubit states that are at an angle of 120 degrees with respect to each other and then hands the state to the opponent, then player B can apply a Positive Operator Valued Measure (POVM) consisting of 3 states that are perpendicular to the states chosen by player A.
> It can be shown that this allows B to be right $100\%$ of the time with only 1 measurement, which is something that is not achievable with a von Neumann measurement on 1 qubit.
See also ("Quantum Theory: Concepts and Methods", A. Peres) for a nice description of the optimal POVM.

Next, we address how we can implement the mentioned POVM by way of a von Neumann measurement, and then how to implement said von Neumann measurement in Q\#. First, we note that the POVM elements are given by the columns of the following matrix:

$$M = \frac{1}{\sqrt{2}}\left(\begin{array}{rrr}
1 & 1 & 1 \\
1 & \omega & \omega^2
\end{array}
\right)$$

where $\omega = e^{2 \pi i/3}$ denotes a primitive third root of unity. Our task will be to implement the rank 1 POVM given by the columns of $M$ via a von Neumann measurement. This can be done by \"embedding\" $M$ into a larger unitary matrix (taking complex conjugate and transpose):

$$M' = \frac{1}{\sqrt{3}}\left(\begin{array}{cccc}
1 & -1 & 1 & 0 \\
1 & -\omega^2 & \omega & 0 \\
1 & -\omega & \omega^2 & 0 \\
0 & 0 & 0 & -i\sqrt{3}
\end{array}
\right)$$

Notice that applying $M'$ to input states given by column $i$ of $M$ (padded with two zeros to make it a vector of length $4$), where $i=0, 1, 2$ will never return the label $i$ as the corresponding vectors are perpendicular.

We are therefore left with the problem of implementing $M'$ as a sequence of elementary quantum gates. Notice that

$$M' \cdot {\rm diag}(1,-1,1,-1) = M' \cdot (\mathbf{1}_2 \otimes Z) =
\frac{1}{\sqrt{3}}\left(\begin{array}{cccc}
1 & 1 & 1 & 0 \\
1 & \omega^2 & \omega & 0 \\
1 & \omega & \omega^2 & 0 \\
0 & 0 & 0 & i\sqrt{3}
\end{array}
\right)$$

Using a technique used in the Rader (also sometimes called Rader-Winograd) decomposition of the discrete Fourier transform ("Discrete Fourier transforms when the number of data samples is prime", C. M. Rader), which reduces it to a cyclic convolution, we apply a $2\times 2$ Fourier transform on the indices $i,j=1,2$ of this matrix (i.e. a block matrix which consists of a direct sum of blocks $\mathbf{1}_1$, $H$, and $\mathbf{1}_1$ which we abbreviate in short as ${\rm diag}(1,H,1)$).

> To implement this in Q#, we can use the following sequence of gates, applied to a 2-qubit array:
>
> ```
> CNOT(qs[1], qs[0]);
> Controlled H([qs[0]], qs[1]);
> CNOT(qs[1], qs[0]);
> ```

This yields

$${\rm diag}(1, H, 1) \cdot M' \cdot (\mathbf{1}_2 \otimes Z) \cdot {\rm diag}(1, H, 1) =
\left(\begin{array}{rrrr}
\frac{1}{\sqrt3} & \sqrt{\frac23} & 0 & 0 \\
\sqrt{\frac23} & -\frac{1}{\sqrt3} & 0 & 0 \\
0 & 0 & i & 0 \\
0 & 0 & 0 & i
\end{array}
\right)$$

This implies that after multiplication with the diagonal operator $(S^\dagger \otimes \mathbf{1}_2)$, we are left with

$${\rm diag}(1, H, 1) \cdot M' \cdot (\mathbf{1}_2 \otimes Z) \cdot {\rm diag}(1, H, 1)\cdot (S^\dagger \otimes \mathbf{1}_2) =
\left(\begin{array}{rrrr}
\frac{1}{\sqrt3} & \sqrt{\frac23} & 0 & 0 \\
\sqrt{\frac23} & -\frac{1}{\sqrt3} & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)$$

which is a zero-controlled rotation $R$ around the $Y$-axis by an angle given by $\arccos \sqrt{\frac23}$ (plus reordering of rows and columns).

> In Q#, we can implement this matrix as the following sequence of gates, applied to a 2-qubit array:
> ```
> CNOT(qs[1], qs[0]);
> X(qs[0]);
> let alpha = ArcCos(Sqrt(2.0 / 3.0));
> (ControlledOnInt(0, Ry))([qs[1]], (-2.0 * alpha, qs[0]));
> ```

Putting everything together, we can implement the matrix $M'$ by applying the inverses of gates:

$$M' = {\rm diag}(1,H,1) \cdot R \cdot (S \otimes \mathbf{1}_2) \cdot {\rm diag}(1,H,1) \cdot (\mathbf{1}_2 \otimes Z)$$

Noting finally, that to apply this sequence of unitaries to a column vector, we have to apply it in reverse when writing it as a program (as actions on vectors are left-associative).

@[solution]({
"id": "distinguishing_states__peres_wooters_game_solution",
"codePath": "Solution.qs"
})
34 changes: 33 additions & 1 deletion katas/content/distinguishing_states/zero_plus/Verification.qs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace Kata.Verification {
open Microsoft.Quantum.Katas;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Random;


operation SetQubitZeroOrPlus (q : Qubit, state : Int) : Unit {
if state != 0 {
Expand All @@ -9,6 +12,35 @@ namespace Kata.Verification {

@EntryPoint()
operation CheckSolution () : Bool {
return DistinguishStates_MultiQubit_Threshold(1, 2, 0.8, SetQubitZeroOrPlus, Kata.IsQubitZeroOrPlus);
let nTotal = 1000;
mutable nOk = 0;
let threshold = 0.8;

use qs = Qubit[1];
for i in 1 .. nTotal {
// get a random integer to define the state of the qubits
let state = DrawRandomInt(0, 1);

// do state prep: convert |0⟩ to outcome with return equal to state
SetQubitZeroOrPlus(qs[0], state);

// get the solution's answer and verify that it's a match
let ans = Kata.IsQubitZeroOrPlus(qs[0]);
if ans == (state == 0) {
set nOk += 1;
}

// we're not checking the state of the qubit after the operation
ResetAll(qs);
}

if IntAsDouble(nOk) < threshold * IntAsDouble(nTotal) {
Message($"{nTotal - nOk} test runs out of {nTotal} returned incorrect state, which does not meet the required threshold of at least {threshold * 100.0}%.");
Message("Incorrect.");
return false;
} else {
Message("Correct!");
return true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Kata {
operation IsQubitZeroPlusOrInconclusive(q : Qubit) : Int {
// Implement your solution here...
return -2;
}
}
20 changes: 20 additions & 0 deletions katas/content/distinguishing_states/zero_plus_inc/Solution.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Kata {
open Microsoft.Quantum.Random;
operation IsQubitZeroPlusOrInconclusive(q : Qubit) : Int {
// Pick a random basis
let basis = DrawRandomInt(0, 1);
if basis == 0 {
// use standard basis
let result = M(q);
// result is One only if the state was |+⟩
return result == One ? 1 | -1;
}
else {
// use Hadamard basis
H(q);
let result = M(q);
// result is One only if the state was |0⟩
return result == One ? 0 | -1;
}
}
}
Loading
Loading