Skip to content

Commit

Permalink
Add tasks 2.x to Distinguishing Unitaries Kata (#1583)
Browse files Browse the repository at this point in the history
This resolves part of #1185 .

---------

Co-authored-by: James Kingdon <[email protected]>
Co-authored-by: Mariia Mykhailova <[email protected]>
Co-authored-by: Mariia Mykhailova <[email protected]>
  • Loading branch information
4 people authored Jun 1, 2024
1 parent e47f5d1 commit 390922a
Show file tree
Hide file tree
Showing 22 changed files with 313 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kata {
operation CNOTDirection (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
// Implement your solution here...

return -1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Kata {
operation CNOTDirection (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
use qs = Qubit[2];
within { X(qs[1]); }
apply { unitary(qs); }
return MResetZ(qs[0]) == Zero ? 0 | 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Kata.Verification {
open Microsoft.Quantum.Katas;

@EntryPoint()
operation CheckSolution() : Bool {
DistinguishUnitaries_Framework([qs => CNOT(qs[0], qs[1]), qs => CNOT(qs[1], qs[0])], Kata.CNOTDirection, ["CNOT_12", "CNOT_21"], 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
**Input:** An operation that implements a two-qubit unitary transformation:
either the $CNOT$ gate with the first qubit as control and the second qubit as target ($CNOT_{12}$)
or the $CNOT$ gate with the second qubit as control and the first qubit as target ($CNOT_{21}$).

**Output:** 0 if the given operation is $CNOT_{12}$, 1 if the given operation is $CNOT_{21}$.

The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
The operation will have Adjoint and Controlled variants defined.
You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**.
38 changes: 38 additions & 0 deletions katas/content/distinguishing_unitaries/cnot_direction/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Again, let's consider the effect of these gates on the basis states:

<table>
<tr>
<th style="text-align:center">State</th>
<th style="text-align:center">$CNOT_{12}$</th>
<th style="text-align:center">$CNOT_{21}$</th>
</tr>
<tr>
<td style="text-align:center">$\ket{00}$</td>
<td style="text-align:center">$\ket{00}$</td>
<td style="text-align:center">$\ket{00}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{01}$</td>
<td style="text-align:center">$\ket{01}$</td>
<td style="text-align:center">$\ket{11}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{10}$</td>
<td style="text-align:center">$\ket{11}$</td>
<td style="text-align:center">$\ket{10}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{11}$</td>
<td style="text-align:center">$\ket{10}$</td>
<td style="text-align:center">$\ket{01}$</td>
</tr>
</table>

We can see that applying these two gates to any basis state other than $\ket{00}$ yields different results, and we can use any of these states to distinguish the unitaries.

Thus, the easiest solution is: prepare two qubits in the $\ket{01}$ state and apply the unitary to them, then measure the first qubit; if it is still `Zero`, the gate is $CNOT_{12}$, otherwise it's $CNOT_{21}$.

@[solution]({
"id": "distinguishing_unitaries__cnot_direction_solution",
"codePath": "Solution.qs"
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kata {
operation DistinguishCNOTfromSWAP (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
// Implement your solution here...

return -1;
}
}
9 changes: 9 additions & 0 deletions katas/content/distinguishing_unitaries/cnot_swap/Solution.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Kata {
operation DistinguishCNOTfromSWAP (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
use qs = Qubit[2];
X(qs[1]);
unitary(qs);
Reset(qs[1]);
return MResetZ(qs[0]) == Zero ? 0 | 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Kata.Verification {
open Microsoft.Quantum.Katas;

@EntryPoint()
operation CheckSolution() : Bool {
DistinguishUnitaries_Framework([qs => CNOT(qs[0], qs[1]), qs => SWAP(qs[0], qs[1])], Kata.DistinguishCNOTfromSWAP, ["CNOT", "SWAP"], 1)
}
}
9 changes: 9 additions & 0 deletions katas/content/distinguishing_unitaries/cnot_swap/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
**Input:** An operation that implements a two-qubit unitary transformation:
either the $CNOT$ gate with the first qubit as control and the second qubit as target ($CNOT_{12}$)
or the $SWAP$ gate.

**Output:** 0 if the given operation is $CNOT_{12}$, 1 if the given operation is $SWAP$.

The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
The operation will have Adjoint and Controlled variants defined.
You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**.
38 changes: 38 additions & 0 deletions katas/content/distinguishing_unitaries/cnot_swap/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Again, let's consider the effect of these gates on the basis states:

<table>
<tr>
<th style="text-align:center">State</th>
<th style="text-align:center">$CNOT_{12}$</th>
<th style="text-align:center">$SWAP$</th>
</tr>
<tr>
<td style="text-align:center">$\ket{00}$</td>
<td style="text-align:center">$\ket{00}$</td>
<td style="text-align:center">$\ket{00}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{01}$</td>
<td style="text-align:center">$\ket{01}$</td>
<td style="text-align:center">$\ket{10}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{10}$</td>
<td style="text-align:center">$\ket{11}$</td>
<td style="text-align:center">$\ket{01}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{11}$</td>
<td style="text-align:center">$\ket{10}$</td>
<td style="text-align:center">$\ket{11}$</td>
</tr>
</table>

Same as in the previous task, applying these two gates to any basis state other than $\ket{00}$ yields different results, and we can use any of these states to distinguish the unitaries.

The easiest solution is: prepare two qubits in the $\ket{01}$ state and apply the unitary to them, then measure the first qubit; if it is still `Zero`, the gate is $CNOT_{12}$, otherwise it's $SWAP$. Remember that this time the second qubit might end up in $\ket{1}$ state, so it needs to be reset to $\ket{0}$ before releasing it.

@[solution]({
"id": "distinguishing_unitaries__cnot_swap_solution",
"codePath": "Solution.qs"
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kata {
operation DistinguishTwoQubitUnitaries (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
// Implement your solution here...

return -1;
}
}
23 changes: 23 additions & 0 deletions katas/content/distinguishing_unitaries/i_cnot_swap/Solution.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Kata {
operation DistinguishTwoQubitUnitaries (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
// First run: apply to |11⟩;
// CNOT₁₂ will give |10⟩, CNOT₂₁ will give |01⟩, I⊗I and SWAP will remain |11⟩
use qs = Qubit[2];
ApplyToEach(X, qs);
unitary(qs);
let ind1 = MeasureInteger(qs);

// Second run: to distinguish I⊗I from SWAP, apply to |01⟩:
// I⊗I will remain |01⟩, SWAP will become |10⟩
X(qs[1]);
unitary(qs);
let ind2 = MeasureInteger(qs);

if ind1 == 1 or ind1 == 2 {
// Respective CNOT
return ind1;
} else {
return ind2 == 1 ? 3 | 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Kata.Verification {
open Microsoft.Quantum.Katas;

@EntryPoint()
operation CheckSolution() : Bool {
DistinguishUnitaries_Framework([ApplyToEachCA(I, _), qs => CNOT(qs[0], qs[1]), qs => CNOT(qs[1], qs[0]), qs => SWAP(qs[0], qs[1])], Kata.DistinguishTwoQubitUnitaries, ["I⊗I", "CNOT_12", "CNOT_21", "SWAP"], 2)
}
}
13 changes: 13 additions & 0 deletions katas/content/distinguishing_unitaries/i_cnot_swap/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
**Input:** An operation that implements a two-qubit unitary transformation:
either the identity ($I \otimes I$), the $CNOT$ gate with one of the qubits as control and the other qubit as a target, or the $SWAP$ gate.

**Output:**

* 0 if the given operation is $I \otimes I$,
* 1 if the given operation is $CNOT_{12}$,
* 2 if the given operation is $CNOT_{21}$,
* 3 if the given operation is $SWAP$.

The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
The operation will have Adjoint and Controlled variants defined.
You are allowed to apply the given operation and its adjoint/controlled variants at most **twice**.
11 changes: 11 additions & 0 deletions katas/content/distinguishing_unitaries/i_cnot_swap/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
In this problem we are allowed to use the given unitary twice, so we can split our decision-making process in two phases:

1. Apply the unitary to the $\ket{11}$ state; $CNOT_{12}$ will yield the $\ket{10}$ state, $CNOT_{21}$ &mdash; $\ket{01}$, and both $I \otimes I$ and $SWAP$ gates will leave the state unchanged.
2. Now to distinguish $I \otimes I$ from $SWAP$, we can use the $\ket{01}$ state: $I \otimes I$ gate will leave it unchanged, while $SWAP$ will yield $\ket{10}$.

Library operation `MeasureInteger` measures all qubits of the array, resets them to $\ket{0}$, and returns the measurement results, using little-endian to convert the bit array to an integer.

@[solution]({
"id": "distinguishing_unitaries__i_cnot_swap_solution",
"codePath": "Solution.qs"
})
40 changes: 40 additions & 0 deletions katas/content/distinguishing_unitaries/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,46 @@ This kata offers you a series of tasks in which you are given one unitary from t
"title": "Distinguishing Multi-Qubit Gates"
})

@[exercise]({
"id": "distinguishing_unitaries__ix_cnot",
"title": "I⊗X or CNOT?",
"path": "./ix_cnot/",
"qsDependencies": [
"../KatasLibrary.qs",
"./Common.qs"
]
})

@[exercise]({
"id": "distinguishing_unitaries__cnot_direction",
"title": "CNOT Direction",
"path": "./cnot_direction/",
"qsDependencies": [
"../KatasLibrary.qs",
"./Common.qs"
]
})

@[exercise]({
"id": "distinguishing_unitaries__cnot_swap",
"title": "CNOT or SWAP?",
"path": "./cnot_swap/",
"qsDependencies": [
"../KatasLibrary.qs",
"./Common.qs"
]
})

@[exercise]({
"id": "distinguishing_unitaries__i_cnot_swap",
"title": "Distinguish Two-Qubit Unitaries",
"path": "./i_cnot_swap/",
"qsDependencies": [
"../KatasLibrary.qs",
"./Common.qs"
]
})

@[section]({
"id": "distinguishing_unitaries__conclusion",
"title": "Conclusion"
Expand Down
7 changes: 7 additions & 0 deletions katas/content/distinguishing_unitaries/ix_cnot/Placeholder.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kata {
operation DistinguishIXfromCNOT (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
// Implement your solution here...

return -1;
}
}
7 changes: 7 additions & 0 deletions katas/content/distinguishing_unitaries/ix_cnot/Solution.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kata {
operation DistinguishIXfromCNOT (unitary : (Qubit[] => Unit is Adj + Ctl)) : Int {
use qs = Qubit[2];
unitary(qs);
return MResetZ(qs[1]) == One ? 0 | 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Kata.Verification {
open Microsoft.Quantum.Katas;

@EntryPoint()
operation CheckSolution() : Bool {
DistinguishUnitaries_Framework([qs => X(qs[1]), qs => CNOT(qs[0], qs[1])], Kata.DistinguishIXfromCNOT, ["I⊗X", "CNOT"], 1)
}
}
8 changes: 8 additions & 0 deletions katas/content/distinguishing_unitaries/ix_cnot/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
**Input:** An operation that implements a two-qubit unitary transformation:
either the $I \otimes X$ (the $X$ gate applied to the second qubit) or the $CNOT$ gate with the first qubit as control and the second qubit as target.

**Output:** 0 if the given operation is $I \otimes X$, 1 if the given operation is the $CNOT$ gate.

The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
The operation will have Adjoint and Controlled variants defined.
You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**.
39 changes: 39 additions & 0 deletions katas/content/distinguishing_unitaries/ix_cnot/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Let's consider the effect of these gates on the basis states:

<table>
<tr>
<th style="text-align:center">State</th>
<th style="text-align:center">$I \otimes X$</th>
<th style="text-align:center">$CNOT$</th>
</tr>
<tr>
<td style="text-align:center">$\ket{00}$</td>
<td style="text-align:center">$\ket{01}$</td>
<td style="text-align:center">$\ket{00}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{01}$</td>
<td style="text-align:center">$\ket{00}$</td>
<td style="text-align:center">$\ket{01}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{10}$</td>
<td style="text-align:center">$\ket{11}$</td>
<td style="text-align:center">$\ket{11}$</td>
</tr>
<tr>
<td style="text-align:center">$\ket{11}$</td>
<td style="text-align:center">$\ket{10}$</td>
<td style="text-align:center">$\ket{10}$</td>
</tr>
</table>

We can see that applying these two gates to states with the first qubit in the $\ket{1}$ state yields identical results, but applying them to states with the first qubit in the $\ket{0}$ state produces states that differ in the second qubuit.
This makes sense, since the $CNOT$ gate is defined as "apply $X$ gate to the target qubit if the control qubit is in the $\ket{1}$ state, and do nothing if it is in the $\ket{0}$ state".

Thus, the easiest solution is: allocate two qubits in the $\ket{00}$ state and apply the unitary to them, then measure the second qubit; if it is `One`, the gate is $I \otimes X$, otherwise it's $CNOT$.

@[solution]({
"id": "distinguishing_unitaries__ix_cnot_solution",
"codePath": "Solution.qs"
})
1 change: 1 addition & 0 deletions katas/content/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"preparing_states",
"single_qubit_measurements",
"multi_qubit_measurements",
"distinguishing_unitaries",
"random_numbers",
"superdense_coding",
"oracles",
Expand Down

0 comments on commit 390922a

Please sign in to comment.