-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'microsoft:main' into Kata-issue-591-add-examples-edit-run
- Loading branch information
Showing
18 changed files
with
419 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,5 +23,6 @@ | |
"solving_sat", | ||
"solving_graph_coloring", | ||
"qft", | ||
"phase_estimation", | ||
"qec_shor" | ||
] |
50 changes: 50 additions & 0 deletions
50
katas/content/phase_estimation/examples/QuantumPhaseEstimationDemo.qs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
namespace Kata { | ||
open Microsoft.Quantum.Convert; | ||
open Microsoft.Quantum.Diagnostics; | ||
open Microsoft.Quantum.Math; | ||
|
||
@EntryPoint() | ||
operation QuantumPhaseEstimationDemo() : Unit { | ||
// Experiment with the parameters to explore algorithm behavior for different eigenphases! | ||
// Use R1Frac(k, n, _) for eigenvalue exp(2π𝑖 k/2^(n+1)), eigenphase k/2^(n+1) | ||
// or R1(theta, _) for eigenvalue exp(2π𝑖 theta/2), eigenphase theta/2 | ||
// Here are some convenient unitaries and their eigenphases | ||
// R1Frac(1, 0, _) | 0.5 | ||
// R1Frac(1, 1, _) | 0.25 | ||
// R1Frac(1, 2, _) | 0.125 | ||
// R1Frac(1, 3, _) | 0.0625 | ||
let U = R1Frac(1, 3, _); | ||
let P = X; // |1⟩ basis state is convenient to experiment with R1 and R1Frac gates | ||
let n = 3; | ||
mutable counts = [0, size = 2 ^ n]; | ||
for _ in 1 .. 100 { | ||
let res = PhaseEstimation(U, P, n); | ||
set counts w/= res <- counts[res] + 1; | ||
} | ||
for i in 0 .. 2 ^ n - 1 { | ||
if counts[i] > 0 { | ||
Message($"Eigenphase {IntAsDouble(i) / IntAsDouble(2 ^ n)} - {counts[i]}%"); | ||
} | ||
} | ||
} | ||
|
||
operation PhaseEstimation( | ||
U : Qubit => Unit is Ctl, | ||
P : Qubit => Unit, | ||
n : Int | ||
) : Int { | ||
use (phaseRegister, eigenstate) = (Qubit[n], Qubit()); | ||
P(eigenstate); | ||
ApplyToEach(H, phaseRegister); | ||
for k in 0 .. n - 1 { | ||
for _ in 1 .. 1 <<< k { | ||
Controlled U([phaseRegister[k]], eigenstate); | ||
} | ||
} | ||
SwapReverseRegister(phaseRegister); | ||
Adjoint ApplyQFT(phaseRegister); | ||
|
||
Reset(eigenstate); | ||
return MeasureInteger(phaseRegister); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
katas/content/phase_estimation/implement_qpe/Placeholder.qs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace Kata { | ||
operation PhaseEstimation( | ||
U : Qubit => Unit is Ctl, | ||
P : Qubit => Unit, | ||
n : Int | ||
) : Int { | ||
// Implement your solution here... | ||
|
||
return 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
namespace Kata { | ||
operation PhaseEstimation( | ||
U : Qubit => Unit is Ctl, | ||
P : Qubit => Unit, | ||
n : Int | ||
) : Int { | ||
use (phaseRegister, eigenstate) = (Qubit[n], Qubit()); | ||
P(eigenstate); | ||
ApplyToEach(H, phaseRegister); | ||
for k in 0 .. n - 1 { | ||
for _ in 1 .. 1 <<< k { | ||
Controlled U([phaseRegister[k]], eigenstate); | ||
} | ||
} | ||
SwapReverseRegister(phaseRegister); | ||
Adjoint ApplyQFT(phaseRegister); | ||
|
||
Reset(eigenstate); | ||
return MeasureInteger(phaseRegister); | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
katas/content/phase_estimation/implement_qpe/Verification.qs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
namespace Kata.Verification { | ||
open Microsoft.Quantum.Unstable.StatePreparation; | ||
|
||
@EntryPoint() | ||
operation CheckSolution() : Bool { | ||
let tests = [ | ||
(Z, I, 1, 0, "Z, |0⟩"), | ||
(Z, X, 1, 1, "Z, |1⟩"), | ||
(X, H, 1, 0, "X, |+⟩"), | ||
(X, q => PreparePureStateD([1., -1.], [q]), 1, 1, "X, |-⟩"), | ||
(S, I, 2, 0, "S, |0⟩"), | ||
(S, X, 2, 1, "S, |1⟩"), | ||
(Z, X, 2, 2, "Z, |1⟩"), // Higher precision than necessary | ||
(T, I, 3, 0, "T, |0⟩"), | ||
(T, X, 3, 1, "T, |1⟩"), | ||
(S, X, 3, 2, "S, |1⟩"), // Higher precision than necessary | ||
(Z, X, 3, 4, "Z, |1⟩"), // Higher precision than necessary | ||
]; | ||
for (U, P, n, expected, msg) in tests { | ||
for _ in 1 .. 10 { // Repeat several times to catch probabilistic failures | ||
let actual = Kata.PhaseEstimation(U, P, n); | ||
if actual != expected { | ||
Message($"Incorrect eigenphase for (U, |ψ⟩, n) = ({msg}, {n}): expected {expected}, got {actual}"); | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
Message("Correct!"); | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
**Inputs:** | ||
|
||
1. A single-qubit unitary $U$. The unitary will have its controlled variant defined. | ||
2. A single-qubit state $\ket{\psi}$, given as a unitary $P$ that prepares it from the $\ket{0}$ state. In other words, the result of applying the unitary $P$ to the state $\ket{0}$ is the $\ket{\psi}$ state: | ||
$$P\ket{0} = \ket{\psi}$$ | ||
3. A positive integer $n$. | ||
|
||
**Output:** Return the eigenphase $\theta$ which corresponds to the eigenstate $\ket{\psi}$, multiplied by $2^n$. You are guaranteed that this eigenvalue has at most $n$ digits of binary precision, so multiplying it by $2^n$ yields an integer. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
To solve this exercise, you need to follow the QPE algorithm as described in this lesson. | ||
|
||
1. Allocate two qubit registers, $n$-qubit `phaseRegister` and single-qubit `eigenstate` (this one can be just an individual qubit rather than a qubit array for simplicity). | ||
2. Prepare the initial state of the algorithm: `eigenstate` in the state $\ket{\psi}$ using the unitary $P$ and `phaseRegister` in the state that is an even superposition of all basis states using Hadamard gates. | ||
3. Apply the controlled $U$ gates using two `for` loops. The outer loop will iterate over the qubits of `phaseRegister`, from the first qubit storing the least significant digit to the last one storing the most significant one. The inner loop will apply controlled $U$ $2^k$ times, where $k$ is the variable used as the outer loop counter. | ||
4. Apply the adjoint QFT. Here, you can use the library operation `ApplyQFT`, keeping in mind that it applies only the rotations part of the quantum Fourier transform. To implement the complete transform using this operation, you need to reverse the order of qubits in the register after applying `ApplyQFT`. Since here you need to use adjoint QFT, you need to reverse the order of qubits before calling `Adjoint ApplyQFT`. | ||
5. Measure the qubits in `phaseRegister` and convert the result to an integer. `MeasureInteger` does exactly that for a register in little endian. You also need to reset the qubit used as the eigenstate before releasing it. | ||
|
||
@[solution]({ | ||
"id": "phase_estimation__implement_qpe_solution", | ||
"codePath": "Solution.qs" | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
katas/content/phase_estimation/one_bit_eigenphase/Placeholder.qs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Kata { | ||
operation OneBitPhaseEstimation(U : Qubit => Unit is Ctl, P : Qubit => Unit) : Int { | ||
// Implement your solution here... | ||
|
||
return 0; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
katas/content/phase_estimation/one_bit_eigenphase/Solution.qs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace Kata { | ||
operation OneBitPhaseEstimation(U : Qubit => Unit is Ctl, P : Qubit => Unit) : Int { | ||
use (control, eigenstate) = (Qubit(), Qubit()); | ||
H(control); | ||
P(eigenstate); | ||
Controlled U([control], eigenstate); | ||
Reset(eigenstate); | ||
|
||
return MResetX(control) == Zero ? 1 | -1; | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
katas/content/phase_estimation/one_bit_eigenphase/Verification.qs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
namespace Kata.Verification { | ||
open Microsoft.Quantum.Unstable.StatePreparation; | ||
|
||
@EntryPoint() | ||
operation CheckSolution() : Bool { | ||
let eigenvectors = [ | ||
(Z, I, 1, "Z, |0⟩"), | ||
(Z, X, -1, "Z, |1⟩"), | ||
(S, I, 1, "S, |0⟩"), | ||
(X, H, 1, "X, |+⟩"), | ||
(X, q => PreparePureStateD([1., -1.], [q]), -1, "X, |-⟩")]; | ||
for (U, P, expected, msg) in eigenvectors { | ||
let actual = Kata.OneBitPhaseEstimation(U, P); | ||
if actual != expected { | ||
Message($"Incorrect eigenvalue for (U, |ψ⟩) = ({msg}): expected {expected}, got {actual}"); | ||
return false; | ||
} | ||
} | ||
|
||
Message("Correct!"); | ||
return true; | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
katas/content/phase_estimation/one_bit_eigenphase/index.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
**Inputs:** | ||
|
||
1. A single-qubit unitary $U$ that is guaranteed to have an eigenvalue $+1$ or $-1$ | ||
(with eigenphases $0$ or $\frac12$, respectively). The unitary will have its controlled variant defined. | ||
2. A single-qubit state $\ket{\psi}$, given as a unitary $P$ that prepares it from the $\ket{0}$ state. In other words, the result of applying the unitary $P$ to the state $\ket{0}$ is the $\ket{\psi}$ state: | ||
$$P\ket{0} = \ket{\psi}$$ | ||
|
||
**Output:** Return the eigenvalue which corresponds to the eigenstate $\ket{\psi}$ ($+1$ or $-1$). | ||
|
||
<details> | ||
<summary><b>Need a hint?</b></summary> | ||
You can do this by allocating exactly two qubits and calling <code>Controlled U<\code> exactly once. | ||
</details> |
19 changes: 19 additions & 0 deletions
19
katas/content/phase_estimation/one_bit_eigenphase/solution.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
What happens if you apply the unitary $U$ to the state $\ket{\psi}$? You end up in one of the states $\ket{\psi}$ or $-\ket{\psi}$, depending on whether the eigenvalue is $+1$ or $-1$. You need to distinguish these two scenarios, but they differ by a global phase, so you can't do this using just one qubit. | ||
|
||
However, if you use the fact that you have access to controlled variant of $U$ and can allocate more than one qubit, you can use a variant of the phase kickback trick to distinguish these scenarios. | ||
|
||
If you apply a controlled $U$ gate to two qubits: the control qubit in the $\ket{+}$ state and the target qubit in the state $\ket{\psi}$, you'll get the following state: | ||
|
||
$$CU \ket{+}\ket{\psi} = \frac1{\sqrt2}(CU \ket{0}\ket{\psi} + CU \ket{1}\ket{\psi}) = \frac1{\sqrt2}(\ket{0}\ket{\psi} + \ket{1}U\ket{\psi}) = $$ | ||
$$= \frac1{\sqrt2}(\ket{0}\ket{\psi} + \ket{1}\lambda\ket{\psi}) = | ||
\begin{cases} | ||
\ket{+}\ket{\psi} \textrm{ if } \lambda = 1 \\ | ||
\ket{-}\ket{\psi} \textrm{ if } \lambda = -1 | ||
\end{cases}$$ | ||
|
||
You only need to measure the control qubit in the Hadamard basis to figure out whether its state is $\ket{+}$ or $\ket{-}$, and you'll be able to tell the value of the eigenvalue $\lambda$. | ||
|
||
@[solution]({ | ||
"id": "phase_estimation__one_bit_eigenphase_solution", | ||
"codePath": "Solution.qs" | ||
}) |
Oops, something went wrong.