diff --git a/katas/content/nonlocal_games/chsh_classical_strategy/solution.md b/katas/content/nonlocal_games/chsh_classical_strategy/solution.md index fb22c98290..f21b32b6d4 100644 --- a/katas/content/nonlocal_games/chsh_classical_strategy/solution.md +++ b/katas/content/nonlocal_games/chsh_classical_strategy/solution.md @@ -1,5 +1,5 @@ -If Alice and Bob always return TRUE, they will have a 75% win rate, since TRUE ⊕ TRUE = FALSE, and the AND operation on their input bits will be FALSE with 75% probability. -Alternatively, Alice and Bob could agree to always return FALSE to achieve the same 75% win probability. A classical strategy cannot achieve a higher success probability. +If Alice and Bob always return TRUE, they will have a $75\%$ win rate, since TRUE $\oplus$ TRUE == FALSE, and the AND operation on their input bits will be FALSE with $75\%$ probability. +Alternatively, Alice and Bob could agree to always return FALSE to achieve the same $75\%$ win probability. A classical strategy cannot achieve a higher success probability. @[solution]({ "id": "nonlocal_games__chsh_classical_strategy_solution", diff --git a/katas/content/nonlocal_games/chsh_classical_win_condition/index.md b/katas/content/nonlocal_games/chsh_classical_win_condition/index.md index bacc59426d..018b6056e3 100644 --- a/katas/content/nonlocal_games/chsh_classical_win_condition/index.md +++ b/katas/content/nonlocal_games/chsh_classical_win_condition/index.md @@ -1,8 +1,8 @@ -**Input:** +**Inputs:** - Alice and Bob's starting bits (X and Y). - Alice and Bob's output bits (A and B). **Output:** - True if Alice and Bob won the CHSH game, that is, if X ∧ Y = A ⊕ B, and false otherwise. + True if Alice and Bob won the CHSH game, that is, if X $\land$ Y = A $\oplus$ B, and false otherwise. diff --git a/katas/content/nonlocal_games/chsh_classical_win_condition/solution.md b/katas/content/nonlocal_games/chsh_classical_win_condition/solution.md index f80b0552ae..708820e27d 100644 --- a/katas/content/nonlocal_games/chsh_classical_win_condition/solution.md +++ b/katas/content/nonlocal_games/chsh_classical_win_condition/solution.md @@ -1,7 +1,10 @@ -There are four input pairs (X, Y) possible, (0,0), (0,1), (1,0), and (1,1), each with 25% probability. +There are four input pairs (X, Y) possible, (0,0), (0,1), (1,0), and (1,1), each with $25\%$ probability. In order to win, Alice and Bob have to output different bits if the input is (1,1), and same bits otherwise. -To check whether the win condition holds, you need to compute $x ∧ y$ and $a ⊕ b$ and to compare these values: if they are equal, Alice and Bob won. You can compute these values using [built-in operators](https://learn.microsoft.com/azure/quantum/user-guide/language/expressions/logicalexpressions): $x ∧ y$ as `x and y` and $a ⊕ b$ as `a != b`. +To check whether the win condition holds, you need to compute X $\land$ Y and A $\oplus$ B and to compare these values: +if they are equal, Alice and Bob won. You can compute these values using +[built-in operators](https://learn.microsoft.com/azure/quantum/user-guide/language/expressions/logicalexpressions): +X $\land$ Y as `x and y` and A $\oplus$ B as `a != b`. @[solution]({ diff --git a/katas/content/nonlocal_games/ghz_classical_game/Placeholder.qs b/katas/content/nonlocal_games/ghz_classical_game/Placeholder.qs new file mode 100644 index 0000000000..1f596eec20 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_game/Placeholder.qs @@ -0,0 +1,7 @@ +namespace Kata { + operation PlayClassicalGHZ (strategies : (Bool => Bool)[], inputs : Bool[]) : Bool[] { + // Implement your solution here... + + return []; + } +} diff --git a/katas/content/nonlocal_games/ghz_classical_game/Solution.qs b/katas/content/nonlocal_games/ghz_classical_game/Solution.qs new file mode 100644 index 0000000000..64a843554c --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_game/Solution.qs @@ -0,0 +1,11 @@ +namespace Kata { + operation PlayClassicalGHZ (strategies : (Bool => Bool)[], inputs : Bool[]) : Bool[] { + let r = inputs[0]; + let s = inputs[1]; + let t = inputs[2]; + let a = strategies[0](r); + let b = strategies[1](s); + let c = strategies[2](t); + return [a, b, c]; + } +} diff --git a/katas/content/nonlocal_games/ghz_classical_game/Verification.qs b/katas/content/nonlocal_games/ghz_classical_game/Verification.qs new file mode 100644 index 0000000000..50cd482431 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_game/Verification.qs @@ -0,0 +1,50 @@ +namespace Kata.Verification { + + // 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]]; + } + + operation TestStrategy (input : Bool, mode : Int) : Bool { + return mode == 0 ? false | mode == 1 ? true | mode == 2 ? input | not input; + } + + operation PlayClassicalGHZ_Reference (strategies : (Bool => Bool)[], inputs : Bool[]) : Bool[] { + let r = inputs[0]; + let s = inputs[1]; + let t = inputs[2]; + let a = strategies[0](r); + let b = strategies[1](s); + let c = strategies[2](t); + return [a, b, c]; + } + + @EntryPoint() + operation CheckSolution() : Bool { + let inputs = RefereeBits(); + for rst in inputs { + // To test the interaction, run it on deterministic strategies (not necessarily good ones) + // This logic helps to detect errors in user PlayClassicalGHZ implementation like + // using the wrong sequence of output bits or not using the strategies at all. + for mode_1 in 0 .. 3 { + for mode_2 in 0 .. 3 { + for mode_3 in 0 .. 3 { + let strategies = [TestStrategy(_, mode_1), TestStrategy(_, mode_2), TestStrategy(_, mode_3)]; + let actual = Kata.PlayClassicalGHZ(strategies, rst); + let expected = PlayClassicalGHZ_Reference(strategies, rst); + if actual != expected { + Message($"Expected {expected}, got {actual} for {rst}"); + return false; + } + } + } + } + } + Message("Correct!"); + true + } +} diff --git a/katas/content/nonlocal_games/ghz_classical_game/index.md b/katas/content/nonlocal_games/ghz_classical_game/index.md new file mode 100644 index 0000000000..33b9fef212 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_game/index.md @@ -0,0 +1,8 @@ +**Inputs:** + +1. An array of three operations which implement the classical strategies of the players (that is, take an input bit and produce an output bit), +2. An array of 3 input bits that should be passed to the players. + +**Output:** + +An array of three bits that will be produced if each player uses their given strategy. diff --git a/katas/content/nonlocal_games/ghz_classical_game/solution.md b/katas/content/nonlocal_games/ghz_classical_game/solution.md new file mode 100644 index 0000000000..f07412d9cf --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_game/solution.md @@ -0,0 +1,6 @@ +You are given both the input bits and the strategy each of the players are using, so you have simply to convert them to the output bits and return those. + +@[solution]({ + "id": "nonlocal_games__ghz_classical_game_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/nonlocal_games/ghz_classical_strategy/Placeholder.qs b/katas/content/nonlocal_games/ghz_classical_strategy/Placeholder.qs new file mode 100644 index 0000000000..117253509b --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_strategy/Placeholder.qs @@ -0,0 +1,19 @@ +namespace Kata { + operation AliceClassical (r : Bool) : Bool { + // Implement your solution here... + + return false; + } + + operation BobClassical (s : Bool) : Bool { + // Implement your solution here... + + return false; + } + + operation CharlieClassical (t : Bool) : Bool { + // Implement your solution here... + + return false; + } +} diff --git a/katas/content/nonlocal_games/ghz_classical_strategy/Solution.qs b/katas/content/nonlocal_games/ghz_classical_strategy/Solution.qs new file mode 100644 index 0000000000..0418ec4aa2 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_strategy/Solution.qs @@ -0,0 +1,14 @@ +namespace Kata { + operation AliceClassical (r : Bool) : Bool { + return true; + } + + operation BobClassical (s : Bool) : Bool { + return true; + } + + operation CharlieClassical (t : Bool) : Bool { + return true; + } +} + diff --git a/katas/content/nonlocal_games/ghz_classical_strategy/Verification.qs b/katas/content/nonlocal_games/ghz_classical_strategy/Verification.qs new file mode 100644 index 0000000000..853abaa47a --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_strategy/Verification.qs @@ -0,0 +1,53 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Logical; + open Microsoft.Quantum.Random; + + function WinCondition_Reference (rst : Bool[], abc : Bool[]) : Bool { + return (rst[0] or rst[1] or rst[2]) == (abc[0] != abc[1] != abc[2]); + } + + // 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]]; + } + + operation PlayClassicalGHZ_Reference (strategies : (Bool => Bool)[], inputs : Bool[]) : Bool[] { + let r = inputs[0]; + let s = inputs[1]; + let t = inputs[2]; + let a = strategies[0](r); + let b = strategies[1](s); + let c = strategies[2](t); + return [a, b, c]; + } + + @EntryPoint() + operation CheckSolution() : Bool { + let inputs = RefereeBits(); + let strategies = [Kata.AliceClassical, Kata.BobClassical, Kata.CharlieClassical]; + + let iterations = 1000; + mutable wins = 0; + for _ in 0 .. iterations - 1 { + for bits in inputs { + let abc = PlayClassicalGHZ_Reference(strategies, bits); + if WinCondition_Reference(bits, abc) { + set wins = wins + 1; + } + } + } + // The solution is correct if the players win 75% (3/4) of the time. + if wins < iterations*Length(inputs)*3/4 { + Message($"Alice, Bob, and Charlie's classical strategy gets {wins} wins out of {iterations*Length(inputs)} possible inputs, which is not optimal"); + return false; + } + Message("Correct!"); + true + } +} diff --git a/katas/content/nonlocal_games/ghz_classical_strategy/index.md b/katas/content/nonlocal_games/ghz_classical_strategy/index.md new file mode 100644 index 0000000000..29b2169b6f --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_strategy/index.md @@ -0,0 +1,11 @@ +In this task you have to implement three functions, one for each player's classical strategy. +Note that they are covered by one test, so you have to implement all of them to pass the test. +In each function, the input is the starting bit of the corresponding player, and it should return the output bit chosen by that player. + +**Input:** + +Alice, Bob, and Charlie's starting bits (R, S, and T). + +**Output:** + +Alice, Bob, and Charlie's output bits (A, B, and C) to maximize their chance of winning. diff --git a/katas/content/nonlocal_games/ghz_classical_strategy/solution.md b/katas/content/nonlocal_games/ghz_classical_strategy/solution.md new file mode 100644 index 0000000000..b5817b8ab6 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_classical_strategy/solution.md @@ -0,0 +1,11 @@ +If all three players return TRUE, then A $\oplus$ B $\oplus$ C == TRUE by necessity (since the sum of their bits is odd). +This will win against inputs 011, 101, and 110 and lose against 000. +Another solution is one player retuns TRUE, and two others return FALSE. + +Since the four above inputs have equal probability, and represent all possible inputs, +either of these deterministic strategies wins with $75\%$ probability. + +@[solution]({ + "id": "nonlocal_games__ghz_classical_strategy_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/nonlocal_games/ghz_win_condition/Placeholder.qs b/katas/content/nonlocal_games/ghz_win_condition/Placeholder.qs new file mode 100644 index 0000000000..3e875360a1 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_win_condition/Placeholder.qs @@ -0,0 +1,7 @@ +namespace Kata { + function WinCondition (rst : Bool[], abc : Bool[]) : Bool { + // Implement your solution here... + + return false; + } +} diff --git a/katas/content/nonlocal_games/ghz_win_condition/Solution.qs b/katas/content/nonlocal_games/ghz_win_condition/Solution.qs new file mode 100644 index 0000000000..3b50a7f155 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_win_condition/Solution.qs @@ -0,0 +1,5 @@ +namespace Kata { + function WinCondition (rst : Bool[], abc : Bool[]) : Bool { + return (rst[0] or rst[1] or rst[2]) == (abc[0] != abc[1] != abc[2]); + } +} diff --git a/katas/content/nonlocal_games/ghz_win_condition/Verification.qs b/katas/content/nonlocal_games/ghz_win_condition/Verification.qs new file mode 100644 index 0000000000..f4d60d7b4f --- /dev/null +++ b/katas/content/nonlocal_games/ghz_win_condition/Verification.qs @@ -0,0 +1,34 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Convert; + + function WinCondition_Reference (rst : Bool[], abc : Bool[]) : Bool { + return (rst[0] or rst[1] or rst[2]) == (abc[0] != abc[1] != abc[2]); + } + + // 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]]; + } + + @EntryPoint() + function CheckSolution() : Bool { + for rst in RefereeBits() { + for i in 0 .. 1 <<< 3 - 1 { + let abc = IntAsBoolArray(i, 3); + let expected = WinCondition_Reference(rst, abc); + let actual = Kata.WinCondition(rst, abc); + + if actual != expected { + Message($"Win condition '{actual}' is wrong for rst={rst}, abc={abc}"); + return false; + } + } + } + Message("Correct!"); + true + } +} diff --git a/katas/content/nonlocal_games/ghz_win_condition/index.md b/katas/content/nonlocal_games/ghz_win_condition/index.md new file mode 100644 index 0000000000..f61068ff2e --- /dev/null +++ b/katas/content/nonlocal_games/ghz_win_condition/index.md @@ -0,0 +1,9 @@ +**Inputs:** + +1. Alice, Bob and Charlie's input bits (r, s and t), stored as an array of length 3. + The input bits will have zero or two bits set to true. +2. Alice, Bob and Charlie's output bits (a, b and c), stored as an array of length 3. + +**Goal:** + +True if Alice, Bob and Charlie won the GHZ game, that is, if R $\lor$ S $\lor$ T = A $\oplus$ B $\oplus$ C, and false otherwise. diff --git a/katas/content/nonlocal_games/ghz_win_condition/solution.md b/katas/content/nonlocal_games/ghz_win_condition/solution.md new file mode 100644 index 0000000000..29524442a7 --- /dev/null +++ b/katas/content/nonlocal_games/ghz_win_condition/solution.md @@ -0,0 +1,11 @@ +There are four inputs possible, (0,0,0), (0,1,1), (1,0,1), and (1,1,0), each with $25\%$ probability. +Therefore, in order to win, the sum of the output bits has to be even if the input is (0,0,0) and odd otherwise. + +To check whether the win condition holds, you need to compute the expressions R $\lor$ S $\lor$ T and A $\oplus$ B $\oplus$ C and to compare them: +if they are equal, the game is won. To compute the expressions, you can use [built-in operators](https://learn.microsoft.com/azure/quantum/user-guide/language/expressions/logicalexpressions): +X $\lor$ Y as `x or y` and A $\oplus$ B as `a != b`. + +@[solution]({ + "id": "nonlocal_games__ghz_win_condition_solution", + "codePath": "Solution.qs" +}) diff --git a/katas/content/nonlocal_games/index.md b/katas/content/nonlocal_games/index.md index 8d1ba9b4b1..2eb25e8aad 100644 --- a/katas/content/nonlocal_games/index.md +++ b/katas/content/nonlocal_games/index.md @@ -31,10 +31,10 @@ In **CHSH Game**, two players (Alice and Bob) try to win the following game: Each of them is given a bit (Alice gets X and Bob gets Y), and they have to return new bits (Alice returns A and Bob returns B) -so that X ∧ Y = A ⊕ B. The trick is, they can not communicate during the game. +so that X $\land$ Y = A $\oplus$ B. The trick is, they can not communicate during the game. -> - ∧ is the standard bitwise AND operator. -> - ⊕ is the exclusive or, or XOR operator, so (P ⊕ Q) is true if exactly one of P and Q is true. +> - $\land$ is the standard bitwise AND operator. +> - $\oplus$ is the exclusive or, or XOR operator, so (P $\oplus$ Q) is true if exactly one of P and Q is true. To start with, let's take a look at how you would play the classical variant of this game without access to any quantum tools. Then, let's proceed with quantum strategies for Alice and Bob. @@ -189,6 +189,43 @@ In the example below you can compare winning percentage of classical and quantum @[example]({"id": "nonlocal_games__chsh_e2edemo", "codePath": "./examples/CHSHGameDemo.qs"}) +@[section]({ + "id": "nonlocal_games__ghz_game", + "title": "GHZ Game" +}) + +In **GHZ Game** three players (Alice, Bob and Charlie) try to win the following game: + +Each of them is given a bit (R, S and T respectively), and they have to return new bits (A, B and C respectively) so that +R $\lor$ S $\lor$ T = A $\oplus$ B $\oplus$ C. +The input bits will have zero or two bits set to true and three or one bits set to false. +The players are free to share information (and even qubits!) before the game starts, but are forbidden from communicating +with each other afterwards. + +> - $\lor$ is the standard bitwise OR operator. +> - $\oplus$ is the exclusive or, or XOR operator, so (P $\oplus$ Q) is true if exactly one of P and Q is true. + +To start with, take a look at how you would play the classical variant of this game without access to any quantum tools. +Then, let's proceed with quantum strategy and game implementation. + +@[exercise]({ + "id": "nonlocal_games__ghz_win_condition", + "title": "Win Condition", + "path": "./ghz_win_condition/" +}) + +@[exercise]({ + "id": "nonlocal_games__ghz_classical_strategy", + "title": "Classical Strategy", + "path": "./ghz_classical_strategy/" +}) + +@[exercise]({ + "id": "nonlocal_games__ghz_classical_game", + "title": "Classical GHZ Game", + "path": "./ghz_classical_game/" +}) + @[section]({ "id": "nonlocal_games__conclusion", "title": "Conclusion"