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

Adds task 1.13 to Superposition Kata #1382

Merged
merged 19 commits into from
Apr 22, 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
7 changes: 7 additions & 0 deletions katas/content/superposition/four_bitstrings/Placeholder.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kata {
operation FourBitstringSuperposition (qs : Qubit[], bits : Bool[][]) : Unit {
// Hint: remember that you can allocate extra qubits.

// Implement your solution here...
}
}
26 changes: 26 additions & 0 deletions katas/content/superposition/four_bitstrings/SolutionA.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace Kata {
operation FourBitstringSuperposition (qs : Qubit[], bits : Bool[][]) : Unit {
use anc = Qubit[2];
// Put two ancillas into equal superposition of 2-qubit basis states
ApplyToEachA(H, anc);

// Set up the right pattern on the main qubits with control on ancillas
for i in 0 .. 3 {
for j in 0 .. Length(qs) - 1 {
if bits[i][j] {
ApplyControlledOnInt(i, X, anc, qs[j]);
}
}
}

// Uncompute the ancillas, using patterns on main qubits as control
for i in 0 .. 3 {
if i % 2 == 1 {
ApplyControlledOnBitString(bits[i], X, qs, anc[0]);
}
if i / 2 == 1 {
ApplyControlledOnBitString(bits[i], X, qs, anc[1]);
}
}
}
}
40 changes: 40 additions & 0 deletions katas/content/superposition/four_bitstrings/SolutionB.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace Kata {
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Math;

operation FourBitstringSuperposition (qs : Qubit[], bits : Bool[][]) : Unit {
FourBitstringSuperposition_Recursive([], qs, bits);
}

operation FourBitstringSuperposition_Recursive (currentBitString : Bool[], qs : Qubit[], bits : Bool[][]) : Unit {
// an array of bit strings whose columns we are considering begin with |0⟩
mutable zeroLeads = [];
// an array of bit strings whose columns we are considering begin with |1⟩
mutable oneLeads = [];
// the number of bit strings we're considering
let rows = Length(bits);
// the current position we're considering
let currentIndex = Length(currentBitString);

if rows >= 1 and currentIndex < Length(qs) {
// figure out what percentage of the bits should be |0⟩
for row in 0 .. rows - 1 {
if bits[row][currentIndex] {
set oneLeads = oneLeads + [bits[row]];
} else {
set zeroLeads = zeroLeads + [bits[row]];
}
}
// rotate the qubit to adjust coefficients based on the previous bit string
// for the first path through, when the bit string has zero length,
// the Controlled version of the rotation will perform a regular rotation
let theta = ArcCos(Sqrt(IntAsDouble(Length(zeroLeads)) / IntAsDouble(rows)));
ApplyControlledOnBitString(currentBitString, Ry, qs[0 .. currentIndex - 1],
(2.0 * theta, qs[currentIndex]));

// call state preparation recursively based on the bit strings so far
FourBitstringSuperposition_Recursive(currentBitString + [false], qs, zeroLeads);
FourBitstringSuperposition_Recursive(currentBitString + [true], qs, oneLeads);
}
}
}
61 changes: 61 additions & 0 deletions katas/content/superposition/four_bitstrings/Verification.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
namespace Kata.Verification {
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Katas;
frtibble marked this conversation as resolved.
Show resolved Hide resolved
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Random;

operation FourBitstringSuperposition_Reference (qs : Qubit[], bits : Bool[][]) : Unit is Adj {
use anc = Qubit[2];
ApplyToEachA(H, anc);

for i in 0 .. 3 {
for j in 0 .. Length(qs) - 1 {
if bits[i][j] {
ApplyControlledOnInt(i, X, anc, qs[j]);
}
}
}

for i in 0 .. 3 {
if i % 2 == 1 {
ApplyControlledOnBitString(bits[i], X, qs, anc[0]);
}
if i / 2 == 1 {
ApplyControlledOnBitString(bits[i], X, qs, anc[1]);
}
}
}

@EntryPoint()
operation CheckSolution() : Bool {

let bits = [[false, false], [false, true], [true, false], [true, true]];
Message($"Testing for bits = {bits}...");
if not CheckOperationsEquivalenceOnZeroStateWithFeedback(
Kata.FourBitstringSuperposition(_, bits),
ApplyToEachA(H, _),
2
) {
return false;
}

let bitstrings = [
[[false, true, false], [true, false, false], [false, false, true], [true, true, false]],
[[true, false, false], [false, false, true], [false, true, false], [true, true, true]],
[[false, false, false], [false, true, false], [true, true, false], [true, false, true]]
];

for bitstring in bitstrings {
Message($"Testing for bits = {bitstring}...");
if not CheckOperationsEquivalenceOnZeroStateWithFeedback(
Kata.FourBitstringSuperposition(_, bitstring),
FourBitstringSuperposition_Reference(_, bitstring),
3
) {
return false;
}
}

return true;
}
}
14 changes: 14 additions & 0 deletions katas/content/superposition/four_bitstrings/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
**Inputs:**

1. $N$ qubits in the $|0 \dots 0\rangle$ state.
2. Four bit strings represented as `Bool[][]` `bits`.

`bits` is an array of size $4 \times N$ which describes the bit strings as follows:
- `bits[i]` describes the *i*th bit string and has $N$ elements.
- All four bit strings will be distinct.

**Goal:** Create an equal superposition of the four basis states given by the bit strings.

**Example:**

For $N = 3$ and `bits = [[false, true, false], [true, false, false], [false, false, true], [true, true, false]]`, the state you need to prepare is $\frac{1}{2} \big(|010\rangle + |100\rangle + |001\rangle + |110\rangle\big)$.
60 changes: 60 additions & 0 deletions katas/content/superposition/four_bitstrings/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
We are going to use the same trick of auxiliary qubits that we used in the previous task.

Since the desired superposition has 4 basis states with equal amplitudes, we are going to need two qubits to define a unique basis to control preparation of each of the basis states in the superposition.

We start by allocating two extra qubits and preparing an equal superposition of all 2-qubit states on them by applying an H gate to each of them:

$$\frac12 (|00\rangle + |01\rangle + |10\rangle + |11\rangle)_a \otimes |0 \dots 0\rangle_r$$

Then, for each of the four given bit strings, we walk through it and prepare the matching basis state on the main register of qubits, using controlled X gates with the corresponding basis state of the auxiliary qubits as control.

For example, when preparing the bit string `bits[0]`, we apply X gates controlled on the basis state $|00\rangle$; when preparing the bit string `bits[1]`, we apply X gates controlled on $|10\rangle$, and so on.

> We can choose an arbitrary matching of the 2-qubit basis states used as controls and the bit strings prepared on the main register.
> Since all amplitudes are the same, the result does not depend on which state controlled which bit string preparation.
> It can be convenient to use indices of the bit strings, converted to little-endian, to control preparation of the bit strings.
> Q# library function [`ApplyControlledOnInt`](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.canon/applycontrolledonint) does exactly that.

After this the system will be in the state

$$\frac12 (|00\rangle_a |bits_0\rangle_r + |10\rangle_a |bits_1\rangle_r + |01\rangle_a |bits_2\rangle_r + |11\rangle_a |bits_3\rangle_r)$$

As the last step, we must uncompute the auxiliary qubits, i.e., return them to the $|00\rangle$ state to unentangle them from the main register.

Same as we did in the previous task, we will use [`ApplyControlledOnBitString`](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.canon/applycontrolledonbitstring) with the corresponding bit string and the X operation as arguments, the quantum register as the control, and the auxiliary qubits as the target.

We will uncompute each of them separately, so one of the auxiliary qubits will be uncomputed with the `bits[1]` and `bits[3]` bit strings as controls, and the other - with the `bits[2]` and `bits[3]`.
frtibble marked this conversation as resolved.
Show resolved Hide resolved

@[solution]({
"id": "superposition__four_bitstrings_solution_a",
"codePath": "./SolutionA.qs"
})

Alternatively, we can leverage the recursion abilities of Q# to create a superposition of the four bit strings. This solution also extends to an arbitrary number of bit strings with no code changes.

For this process we will look at the first bits of each string and adjust the probability of measuring a $|0\rangle$ or $|1\rangle$ accordingly on the first qubit of our answer. We will then recursively call (as needed) the process again to adjust the probabilities of measurement on the second bit depending on the first bit. This process recurses until no more input bits are provided.

Consider, for example, the following four bit strings on which to create a superposition: $|001\rangle, |101\rangle, |111\rangle, |110\rangle$.

We can rewrite the superposition state we need to prepare as

$$\frac12 \big(|001\rangle + |101\rangle + |111\rangle + |110\rangle \big) = \frac12 |0\rangle \otimes |01\rangle + \frac{\sqrt3}{2} |1\rangle \otimes \frac{1}{\sqrt3} \big(|10\rangle + |11\rangle + |10\rangle \big)$$

As the first step of the solution, we need to prepare a state $\frac12 |0\rangle + \frac{\sqrt3}{2} |1\rangle$ on the first qubit (to measure $|0\rangle$ with $\frac14$ probability and to measure $|1\rangle$ with $\frac34$ probability). To do this, we will apply an [`Ry`](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/ry) rotation to the first qubit.

After this, we'll need to prepare the rest of the qubits in appropriate states depending on the state of the first qubit - state $|01\rangle$ if the first qubit is in state $|0\rangle$ and state $\frac{1}{\sqrt3} \big(|10\rangle + |11\rangle + |10\rangle \big)$ if the first qubit is in state $|1\rangle$. We can do this recursively using the same logic. Let's finish walking through this example in detail.

The second qubit of the recursion follows similarly but depends on the first qubit. If the first qubit measures $|0\rangle$, then we want the second qubit to measure $|0\rangle$ with 100% probability, but if it measures $|1\rangle$, we want it to measure $|0\rangle$ with $\frac13$ probability and $|1\rangle$ with $\frac23$ probability. For this, we can do a controlled [`Ry`](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/ry) rotation on the second qubit with the first qubit as control.

The third qubit in this example will have three cases because it depends on the first two qubits; this follows naturally from the recursion.

1. If the first two qubits measure $|00\rangle$, then we need the third qubit to measure $|0\rangle$ with 100% probability.
2. If the first two qubits measure $|10\rangle$, then we need the third qubit to measure $|1\rangle$ with 100% probability.
3. If the first two qubits measure $|11\rangle$, then we need the third qubit to measure $|0\rangle$ with $\frac12$ probability and $|1\rangle$ with $\frac12$ probability. Just as with the second qubit, a controlled [`Ry`](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.intrinsic/ry) rotation on the third qubit will accomplish this goal.

> We will use [`ApplyControlledOnBitString`](https://learn.microsoft.com/qsharp/api/qsharp-lang/microsoft.quantum.canon/applycontrolledonbitstring) operation to perform rotations depending on the state of several previous qubits.

@[solution]({
"id": "superposition__four_bitstrings_solution_b",
"codePath": "./SolutionB.qs"
})
10 changes: 10 additions & 0 deletions katas/content/superposition/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ This kata is designed to get you familiar with the concept of superposition and
]
})

@[exercise]({
"id": "superposition__four_bitstrings",
"title": "Four Bit Strings",
"path": "./four_bitstrings/",
"qsDependencies": [
"../KatasLibrary.qs",
"./Common.qs"
]
})

@[section]({
"id": "superposition__arbitrary_rotations",
"title": "Arbitrary Rotations"
Expand Down
Loading