Skip to content

Commit

Permalink
Migrate nonlocal games microsoft#1596 task2 GHZ quantum
Browse files Browse the repository at this point in the history
  • Loading branch information
ggridin committed Aug 13, 2024
1 parent a8b00c8 commit f1c08d7
Show file tree
Hide file tree
Showing 16 changed files with 363 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Kata {
operation CreateEntangledTriple (qs : Qubit[]) : Unit {
// Implement your solution here...
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Kata {
operation CreateEntangledTriple (qs : Qubit[]) : Unit is Adj {
X(qs[0]);
X(qs[1]);

H(qs[0]);
H(qs[1]);
// At this point we have (|000⟩ - |010⟩ - |100⟩ + |110⟩) / 2

// Flip the sign of the last term
Controlled Z([qs[0]], qs[1]);

// Flip the state of the last qubit for the two middle terms
ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace Kata.Verification {
open Microsoft.Quantum.Diagnostics;

operation CreateEntangledTriple_Reference (qs : Qubit[]) : Unit is Adj {
X(qs[0]);
X(qs[1]);

H(qs[0]);
H(qs[1]);
// At this point we have (|000⟩ - |010⟩ - |100⟩ + |110⟩) / 2

// Flip the sign of the last term
Controlled Z([qs[0]], qs[1]);

// Flip the state of the last qubit for the two middle terms
ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
}

@EntryPoint()
operation CheckSolution() : Bool {
use qs = Qubit[3];
// apply operation that needs to be tested
Kata.CreateEntangledTriple(qs);

// apply adjoint reference operation and check that the result is |0ᴺ⟩
Adjoint CreateEntangledTriple_Reference(qs);

// check that all qubits end up in |0⟩ state
let result = CheckAllZero(qs);
ResetAll(qs);
if result {
Message("Correct!");
}
else {
Message("Entangled triple is not implemented correctly");
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
In the quantum version of the game, the players still can not communicate during the game, but they are allowed to share
qubits from an entangled triple before the start of the game.

**Input:**
- An array of three qubits in the $|000\rangle$ state.

**Goal:**
- Create the entangled state $\ket{\Phi} = \frac{1}{2} \big(\ket{000} - \ket{011} - \ket{101} - \ket{110} \big)$ on these qubits.
This state is equivalent to GHZ state $\frac{1}{\sqrt{2}} (\big(\ket{000} + \ket{111} \big)$ up to local unitary operation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
1. Apply an X gate to the first and the second qubits to get the $\ket{110}$ state.
2. Appy an H gate to the first and the second qubits to get the following state:
$\frac12 \big( \ket{000} - \ket{010} - \ket{100} + \ket{110} \big)$
3. Flip the sign of the last term using a controlled Z gate with the first qubit as control and the second qubit as target (or vice versa):
$\frac12 \big( \ket{000} - \ket{010} - \ket{100} -{\color{blue}\ket{110}} \big)$
4. Now we have the right signs for each term, and the first and the last terms match those of the state we're preparing, so we just need to adjust the two middle terms.
To do this, we can use [ControlledOnBitString](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.canon.controlledonbitstring) operation to flip the state of the last qubit if the first two qubits are in $\ket{01}$ or in $\ket{10}$ states, which gives us:
$\frac{1}{2} \big(\ket{000} - {\color{blue}\ket{011}} - {\color{blue}\ket{101}} - \ket{110} \big)$

@[solution]({
"id": "nonlocal_games__ghz_create_entangled_triple_solution",
"codePath": "Solution.qs"
})
7 changes: 7 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_game/Placeholder.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kata {
operation PlayQuantumGHZ (strategies : ((Bool, Qubit) => Bool)[], inputs : Bool[]) : Bool[] {
// Implement your solution here...

return [];
}
}
32 changes: 32 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_game/Solution.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace Kata {
operation CreateEntangledTriple (qs : Qubit[]) : Unit is Adj {
X(qs[0]);
X(qs[1]);

H(qs[0]);
H(qs[1]);
// At this point we have (|000⟩ - |010⟩ - |100⟩ + |110⟩) / 2

// Flip the sign of the last term
Controlled Z([qs[0]], qs[1]);

// Flip the state of the last qubit for the two middle terms
ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
}

operation PlayQuantumGHZ (strategies : ((Bool, Qubit) => Bool)[], inputs : Bool[]) : Bool[] {
use qs = Qubit[3];
CreateEntangledTriple(qs);

let r = inputs[0];
let s = inputs[1];
let t = inputs[2];
let a = strategies[0](r, qs[0]);
let b = strategies[1](s, qs[1]);
let c = strategies[2](t, qs[2]);

ResetAll(qs);
return [a, b, c];
}
}
93 changes: 93 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_game/Verification.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace Kata.Verification {
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Logical;

// All possible starting bits (r, s and t) that the referee can give
// to Alice, Bob and Charlie.
function RefereeBits () : Bool[][] {
return [[false, false, false],
[true, true, false],
[false, true, true],
[true, false, true]];
}

function WinCondition_Reference (rst : Bool[], abc : Bool[]) : Bool {
return (rst[0] or rst[1] or rst[2]) == Xor(Xor(abc[0], abc[1]), abc[2]);
}

operation AliceQuantum_Reference (bit : Bool, qubit : Qubit) : Bool {
if bit {
H(qubit);
}
return M(qubit) == One;
}

operation BobQuantum_Reference (bit : Bool, qubit : Qubit) : Bool {
if bit {
H(qubit);
}
return M(qubit) == One;
}

operation CharlieQuantum_Reference (bit : Bool, qubit : Qubit) : Bool {
if bit {
H(qubit);
}
return M(qubit) == One;
}

operation CreateEntangledTriple_Reference (qs : Qubit[]) : Unit is Adj {
X(qs[0]);
X(qs[1]);

H(qs[0]);
H(qs[1]);
// At this point we have (|000⟩ - |010⟩ - |100⟩ + |110⟩) / 2

// Flip the sign of the last term
Controlled Z([qs[0]], qs[1]);

// Flip the state of the last qubit for the two middle terms
ApplyControlledOnBitString([false, true], X, [qs[0], qs[1]], qs[2]);
ApplyControlledOnBitString([true, false], X, [qs[0], qs[1]], qs[2]);
}

operation PlayQuantumGHZ_Reference (strategies : ((Bool, Qubit) => Bool)[], inputs : Bool[]) : Bool[] {
use qs = Qubit[3];
CreateEntangledTriple_Reference(qs);
let r = inputs[0];
let s = inputs[1];
let t = inputs[2];
let a = strategies[0](r, qs[0]);
let b = strategies[1](s, qs[1]);
let c = strategies[2](t, qs[2]);

ResetAll(qs);
return [a, b, c];
}

@EntryPoint()
operation CheckSolution() : Bool {
let inputs = RefereeBits();
let strategies = [AliceQuantum_Reference, BobQuantum_Reference, CharlieQuantum_Reference];
for rst in inputs {
let actualBits = Kata.PlayQuantumGHZ(strategies, rst);
if Length(actualBits) != 3 {
Message($"Expected 3 bits from PlayQuantumGHZ, got {Length(actualBits)}");
return false;
}
let expectedBits = PlayQuantumGHZ_Reference(strategies, rst);
let actualWin = WinCondition_Reference(rst, actualBits);
let expectedWin = WinCondition_Reference(rst, expectedBits);
if actualWin != expectedWin {
Message($"Expected win={expectedWin} {expectedBits}, got {actualBits} for {rst}");
return false;
}
else {
Message($"Cool {expectedBits}, got {actualBits} for {rst}");
}
}
true
}
}
8 changes: 8 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_game/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Let's play the GHZ game using the quantum strategy.

**Inputs:**
1. An array of three operations which implement the quantum strategies of the players,
2. An array of 3 input bits that should be passed to the players.

**Goal:**
An array of three bits that will be produced if each player uses their given strategy.
11 changes: 11 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_game/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Putting together the building blocks we've implemented into a strategy is very simple:

1. Allocate three qubits and prepare our entangled state on them (using `CreateEntangledTriple`).
2. Send one of the qubits to each of the players (this step is \"virtual\", not directly reflected in Q# code, other than making sure that the strategies each act on their qubit only).
3. Have the players perform their measurements on their respective qubits using corresponding elements of the `strategies` array.
4. Return their measurement results.

@[solution]({
"id": "nonlocal_games__ghz_quantum_game_solution",
"codePath": "Solution.qs"
})
19 changes: 19 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_strategy/Placeholder.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Kata {
operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
// Implement your solution here...

return false;
}

operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
// Implement your solution here...

return false;
}

operation CharlieQuantum (bit : Bool, qubit : Qubit) : Bool {
// Implement your solution here...

return false;
}
}
27 changes: 27 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_strategy/Solution.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Kata {
operation AliceQuantum (bit : Bool, qubit : Qubit) : Bool {
if bit {
let res = MResetX(qubit);
return res == One;
}
let res = MResetZ(qubit);
return res == One;
}

operation BobQuantum (bit : Bool, qubit : Qubit) : Bool {
if bit {
let res = MResetX(qubit);
return res == One;
}
let res = MResetZ(qubit);
return res == One;
}

// alternative implementation
operation CharlieQuantum (bit : Bool, qubit : Qubit) : Bool {
if bit {
H(qubit);
}
return M(qubit) == One;
}
}
44 changes: 44 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_strategy/Verification.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace Kata.Verification {

@EntryPoint()
operation CheckSolution() : Bool {
use q = Qubit();
for _ in 1 .. 4 {
// repeat 4 times since we are testing a measurement and wrong basis still might get
// the correct answer, reduces probability of false positives
if (Kata.AliceQuantum(false, q) != false) {
Message("|0⟩ not measured as false");
Reset(q);
return false;
}

// apply the Pauli X gate
X(q);
if (Kata.AliceQuantum(false, q) != true) {
Message("|1⟩ not measured as true");
Reset(q);
return false;
}

// apply the Hadamard gate
H(q);
if (Kata.AliceQuantum(true, q) != false) {
Message("|+⟩ not measured as false");
Reset(q);
return false;
}

// apply the Pauli X and then the Hadamard gate
X(q);
H(q);
if (Kata.AliceQuantum(true, q) != true) {
Message("|-⟩ not measured as true");
Reset(q);
return false;
}
Reset(q);
}
Message("Correct!");
true
}
}
8 changes: 8 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_strategy/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
**Inputs:**

1. The input bit for one of each of the players (R, S and T respectively),
2. That player's qubit of the entangled triple shared between the players.

**Goal:**
Measure the qubit in the Z basis if the bit is 0 (FALSE), or the X basis if the bit is 1 (TRUE), and return the result.
The state of the qubit after the operation does not matter.
12 changes: 12 additions & 0 deletions katas/content/nonlocal_games/ghz_quantum_strategy/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
In Q#, you can perform measurements in a specific basis using either the
[Measure operation](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.intrinsic.measure)
or convenient shorthands for measure-and-reset-to-$\ket{0}$ sequence of operations
[MResetZ](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.measurement.mresetz) and
[MResetX](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.measurement.mresetx).

Alternatively, you can recall that measuring the qubit in the X basis is equivalent to applying an H gate to it and measuring it in the Z basis.

@[solution]({
"id": "nonlocal_games__ghz_quantum_strategy_solution",
"codePath": "Solution.qs"
})
18 changes: 18 additions & 0 deletions katas/content/nonlocal_games/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,24 @@ Then, let's proceed with quantum strategy and game implementation.
"path": "./ghz_classical_game/"
})

@[exercise]({
"id": "nonlocal_games__ghz_create_ghz_state",
"title": "Create Entangled Triple",
"path": "./ghz_create_entangled_triple/"
})

@[exercise]({
"id": "nonlocal_games__ghz_quantum_strategy",
"title": "Quantum Strategy",
"path": "./ghz_quantum_strategy/"
})

@[exercise]({
"id": "nonlocal_games__ghz_quantum_game",
"title": "Quantum Game",
"path": "./ghz_quantum_game/"
})

@[section]({
"id": "nonlocal_games__conclusion",
"title": "Conclusion"
Expand Down

0 comments on commit f1c08d7

Please sign in to comment.