diff --git a/katas/content/multi_qubit_gates/entangle_qubits/Placeholder.qs b/katas/content/multi_qubit_gates/entangle_qubits/Placeholder.qs new file mode 100644 index 0000000000..f5ee355d30 --- /dev/null +++ b/katas/content/multi_qubit_gates/entangle_qubits/Placeholder.qs @@ -0,0 +1,6 @@ +namespace Kata { + operation EntangleQubits (qs : Qubit[]) : Unit is Adj + Ctl { + // Implement your solution here... + + } +} \ No newline at end of file diff --git a/katas/content/multi_qubit_gates/entangle_qubits/Solution.qs b/katas/content/multi_qubit_gates/entangle_qubits/Solution.qs new file mode 100644 index 0000000000..3a2b89e267 --- /dev/null +++ b/katas/content/multi_qubit_gates/entangle_qubits/Solution.qs @@ -0,0 +1,5 @@ +namespace Kata { + operation EntangleQubits (qs : Qubit[]) : Unit is Adj + Ctl { + CNOT(qs[0], qs[1]); + } +} \ No newline at end of file diff --git a/katas/content/multi_qubit_gates/entangle_qubits/Verification.qs b/katas/content/multi_qubit_gates/entangle_qubits/Verification.qs new file mode 100644 index 0000000000..822d40def7 --- /dev/null +++ b/katas/content/multi_qubit_gates/entangle_qubits/Verification.qs @@ -0,0 +1,52 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Convert; + + operation EntangleQubits (qs : Qubit[]) : Unit is Adj + Ctl { + CNOT(qs[0], qs[1]); + } + + operation CheckOperationsEquivalenceOnInitialStateStrict( + initialState : Qubit[] => Unit is Adj, + op : (Qubit[] => Unit is Adj + Ctl), + reference : (Qubit[] => Unit is Adj + Ctl), + inputSize : Int + ) : Bool { + use (control, target) = (Qubit(), Qubit[inputSize]); + within { + H(control); + initialState(target); + } + apply { + Controlled op([control], target); + Adjoint Controlled reference([control], target); + } + let isCorrect = CheckAllZero([control] + target); + ResetAll([control] + target); + isCorrect + } + + operation CheckSolution() : Bool { + let range = 10; + for i in 0 .. range - 1 { + let angle = 2.0 * PI() * IntAsDouble(i) / IntAsDouble(range); + let initialState = qs => Ry(2.0 * angle, qs[0]); + let isCorrect = CheckOperationsEquivalenceOnInitialStateStrict( + initialState, + Kata.EntangleQubits, + EntangleQubits, + 2); + if not isCorrect { + Message("Incorrect"); + Message($"Test fails for alpha = {Cos(angle)}, beta = {Sin(angle)}."); + ShowQuantumStateComparison(2, initialState, Kata.EntangleQubits, EntangleQubits); + return false; + } + } + + Message("Correct!"); + true + } +} \ No newline at end of file diff --git a/katas/content/multi_qubit_gates/entangle_qubits/index.md b/katas/content/multi_qubit_gates/entangle_qubits/index.md new file mode 100644 index 0000000000..07ce922724 --- /dev/null +++ b/katas/content/multi_qubit_gates/entangle_qubits/index.md @@ -0,0 +1,5 @@ +**Input:** Two unentangled qubits (stored in an array of length 2). +The first qubit will be in state $|\psi\rangle = \alpha |0\rangle + \beta |1\rangle$, the second - in state $|0\rangle$ +(this can be written as two-qubit state $\big(\alpha |0\rangle + \beta |1\rangle \big) \otimes |0\rangle = \alpha |00\rangle + \beta |10\rangle$). + +**Goal:** Change the two-qubit state to $\alpha |00\rangle + \beta |11\rangle$. diff --git a/katas/content/multi_qubit_gates/entangle_qubits/solution.md b/katas/content/multi_qubit_gates/entangle_qubits/solution.md new file mode 100644 index 0000000000..7326c09106 --- /dev/null +++ b/katas/content/multi_qubit_gates/entangle_qubits/solution.md @@ -0,0 +1,11 @@ +Let's denote the first qubit in state $\alpha |0\rangle + \beta |1\rangle$ as A and the second qubit in state $|0\rangle$ as B. + +Compare our input state $\alpha |0_A0_B\rangle + \beta |1_A0_B\rangle$ with the goal state $\alpha |0_A0_B\rangle + \beta |1_A1_B\rangle$. +We want to pass our input qubit through a gate or gates (to be decided) that do the following. If qubit A is in the $|0\rangle$ state, then we want to leave qubit B alone (the first term of the superposition). +However, if A is in the $|1\rangle$ state, we want to flip qubit B from $|0\rangle$ into $|1\rangle$ state. In other words, the state of B is to be made contingent upon the state of A. +This is exactly the effect of the $CNOT$ gate. Depending upon the state of the **control** qubit (A in our case), the value of the controlled or **target** qubit (B in our case) is inverted or unchanged. Thus, we get the goal state $\alpha |00\rangle + \beta |11\rangle$. + +@[solution]({ + "id": "multi_qubit_gates__entangle_qubits_solution", + "codePath": "./Solution.qs" +}) diff --git a/katas/content/multi_qubit_gates/index.md b/katas/content/multi_qubit_gates/index.md index c5009d5e50..9fa2736944 100644 --- a/katas/content/multi_qubit_gates/index.md +++ b/katas/content/multi_qubit_gates/index.md @@ -121,6 +121,16 @@ $$\alpha|00\rangle + \beta|11\rangle$$ The $CNOT$ gate is self-adjoint: applying it for the second time reverses its effect. + +@[exercise]({ + "id": "multi_qubit_gates__entangle_qubits", + "title": "Entangle Qubits", + "path": "./entangle_qubits/", + "qsDependencies": [ + "../KatasLibrary.qs" + ] +}) + @[exercise]({ "id": "multi_qubit_gates__preparing_bell_state", "title": "Preparing a Bell State", @@ -130,6 +140,62 @@ The $CNOT$ gate is self-adjoint: applying it for the second time reverses its ef ] }) +@[section]({ + "id": "multi_qubit_gates__cz_gate", + "title": "CZ Gate" +}) + + +The $CZ$ ("controlled-Z") gate is a two-qubit gate, with one qubit referred to as the **control** qubit, and the other as the **target** qubit. Interestingly, for the $CZ$ gate it doesn't matter which qubit is control and which is target - the effect of the gate is the same either way! + +The $CZ$ gate acts as a conditional gate: if the control qubit is in state $|1\rangle$, it applies the $Z$ gate to the target qubit, otherwise it does nothing. + + + + + + + + + + + + + + +
GateMatrixApplying to $|\psi\rangle = \alpha|00\rangle + \beta|01\rangle + \gamma|10\rangle + \delta|11\rangle$Applying to basis states
$CZ$ + $$\begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & -1 + \end{bmatrix}$$ + $CZ|\psi\rangle = \alpha|00\rangle + \beta|01\rangle + \gamma|10\rangle - \delta|11\rangle$ + $$CZ|00\rangle = |00\rangle$$ + $$CZ|01\rangle = |01\rangle$$ + $$CZ|10\rangle = |10\rangle$$ + $$CZ|11\rangle = -|11\rangle$$ +
+ +The $CZ$ gate is particularly useful for creating and manipulating entangled states where the phase of the quantum state is crucial. Consider the following separable state: + +$$\big(\alpha|0\rangle + \beta|1\rangle\big) \otimes \big(\gamma|0\rangle + \delta|1\rangle\big) = \alpha\gamma|00\rangle + \alpha\delta|01\rangle + \beta\gamma|10\rangle + \beta\delta|11\rangle$$ + +If we apply the $CZ$ gate to it, with the first qubit as the control and the second as the target (or vice versa), we get the following state, which can no longer be separated: + +$$\alpha\gamma|00\rangle + \alpha\delta|01\rangle + \beta\gamma|10\rangle - \beta\delta|11\rangle$$ + +The $CZ$ gate is also self-adjoint: applying it a second time reverses its effect, similar to the $CNOT$ gate. + +@[exercise]({ + "id": "multi_qubit_gates__relative_phase_minusone", + "title": "Relative Phase -1", + "path": "./relative_phase_minusone/", + "qsDependencies": [ + "../KatasLibrary.qs" + ] +}) + @[section]({ "id": "multi_qubit_gates__ket_bra_representation", "title": "Ket-Bra Representation" diff --git a/katas/content/multi_qubit_gates/relative_phase_minusone/Placeholder.qs b/katas/content/multi_qubit_gates/relative_phase_minusone/Placeholder.qs new file mode 100644 index 0000000000..c5b83b3112 --- /dev/null +++ b/katas/content/multi_qubit_gates/relative_phase_minusone/Placeholder.qs @@ -0,0 +1,6 @@ +namespace Kata { + operation RelativePhaseMinusOne (qs : Qubit[]) : Unit is Adj + Ctl { + // Implement your solution here... + + } +} \ No newline at end of file diff --git a/katas/content/multi_qubit_gates/relative_phase_minusone/SolutionA.qs b/katas/content/multi_qubit_gates/relative_phase_minusone/SolutionA.qs new file mode 100644 index 0000000000..119e4afa7c --- /dev/null +++ b/katas/content/multi_qubit_gates/relative_phase_minusone/SolutionA.qs @@ -0,0 +1,5 @@ +namespace Kata { + operation RelativePhaseMinusOne (qs : Qubit[]) : Unit is Adj + Ctl { + CZ(qs[0], qs[1]); + } +} \ No newline at end of file diff --git a/katas/content/multi_qubit_gates/relative_phase_minusone/SolutionB.qs b/katas/content/multi_qubit_gates/relative_phase_minusone/SolutionB.qs new file mode 100644 index 0000000000..57fcf1a75e --- /dev/null +++ b/katas/content/multi_qubit_gates/relative_phase_minusone/SolutionB.qs @@ -0,0 +1,5 @@ +namespace Kata { + operation RelativePhaseMinusOne (qs : Qubit[]) : Unit is Adj + Ctl { + Controlled Z([qs[0]], qs[1]); + } +} \ No newline at end of file diff --git a/katas/content/multi_qubit_gates/relative_phase_minusone/Verification.qs b/katas/content/multi_qubit_gates/relative_phase_minusone/Verification.qs new file mode 100644 index 0000000000..e0c35e8609 --- /dev/null +++ b/katas/content/multi_qubit_gates/relative_phase_minusone/Verification.qs @@ -0,0 +1,47 @@ +namespace Kata.Verification { + open Microsoft.Quantum.Katas; + open Microsoft.Quantum.Diagnostics; + + operation PrepareState(qs : Qubit[]) : Unit is Adj + Ctl { + ApplyToEachCA(H, qs); + } + operation RelativePhaseMinusOne (qs : Qubit[]) : Unit is Adj + Ctl { + CZ(qs[0], qs[1]); + } + + operation CheckOperationsEquivalenceOnInitialStateStrict( + initialState : Qubit[] => Unit is Adj, + op : (Qubit[] => Unit is Adj + Ctl), + reference : (Qubit[] => Unit is Adj + Ctl), + inputSize : Int + ) : Bool { + use (control, target) = (Qubit(), Qubit[inputSize]); + within { + H(control); + initialState(target); + } + apply { + Controlled op([control], target); + Adjoint Controlled reference([control], target); + } + let isCorrect = CheckAllZero([control] + target); + ResetAll([control] + target); + isCorrect + } + + operation CheckSolution() : Bool { + let isCorrect = CheckOperationsEquivalenceOnInitialStateStrict( + PrepareState, + Kata.RelativePhaseMinusOne, + RelativePhaseMinusOne, + 2); + if isCorrect { + Message("Correct!"); + } else { + Message("Incorrect"); + ShowQuantumStateComparison(2, PrepareState, Kata.RelativePhaseMinusOne, RelativePhaseMinusOne); + } + + return isCorrect; + } +} \ No newline at end of file diff --git a/katas/content/multi_qubit_gates/relative_phase_minusone/index.md b/katas/content/multi_qubit_gates/relative_phase_minusone/index.md new file mode 100644 index 0000000000..33bcf050f4 --- /dev/null +++ b/katas/content/multi_qubit_gates/relative_phase_minusone/index.md @@ -0,0 +1,3 @@ +**Input:** Two unentangled qubits (stored in an array of length 2) in state $|+\rangle \otimes |+\rangle = \frac{1}{2} \big( |00\rangle + |01\rangle + |10\rangle {\color{blue}+} |11\rangle \big)$. + +**Goal:** Change the two-qubit state to $\frac{1}{2} \big( |00\rangle + |01\rangle + |10\rangle {\color{red}-} |11\rangle \big)$. diff --git a/katas/content/multi_qubit_gates/relative_phase_minusone/solution.md b/katas/content/multi_qubit_gates/relative_phase_minusone/solution.md new file mode 100644 index 0000000000..b94bb4f436 --- /dev/null +++ b/katas/content/multi_qubit_gates/relative_phase_minusone/solution.md @@ -0,0 +1,22 @@ +Firstly we notice that we are dealing with an unentangled pair of qubits. +In vector form the transformation we need is +$$ +\frac{1}{2}\begin{bmatrix}1\\\ 1\\\ 1\\\ 1\\\ \end{bmatrix} +\rightarrow +\frac{1}{2}\begin{bmatrix}1\\\ 1\\\ 1\\\ -1\\\ \end{bmatrix} +$$ + +All that needs to happen to change the input into the goal is that the $|11\rangle$ basis state needs to have its sign flipped. + +We remember that the Pauli $Z$ gate flips signs in the single qubit case, and that $CZ$ is the 2-qubit version of this gate. And indeed, the effect of the $CZ$ gate is exactly the transformation we're looking for here. + +@[solution]({ +"id": "multi_qubit_gates__two_qubit_gate_2_solution_a", +"codePath": "./SolutionA.qs" +}) +Alternatively, we can express this gate using the intrinsic gate Z and its controlled variant using the Controlled functor: + +@[solution]({ +"id": "multi_qubit_gates__two_qubit_gate_2_solution_b", +"codePath": "./SolutionB.qs" +})