Updating Katas to QDK 0.6 (#111)
* Update the katas to use QDK 0.6.1905.301. * Add mechanism to verify that the reference solutions actually solve all tasks of a Notebook correctly. Co-Authored-By: Bettina Heim <34236215+bettinaheim@users.noreply.github.com> Co-Authored-By: Andres Paz <anpaz@microsoft.com>
This commit is contained in:
Родитель
df491c9844
Коммит
7519eb3f74
|
@ -17,6 +17,7 @@ Tests/build
|
|||
# test outputs
|
||||
TestResults/
|
||||
*.qxe
|
||||
Check.ipynb
|
||||
|
||||
# Random VS files
|
||||
*.suo
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%package Microsoft.Quantum.Katas::0.5.1904.1302"
|
||||
"%package Microsoft.Quantum.Katas::0.6.1905.301"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -46,13 +46,13 @@
|
|||
"> The package versions in the output of the cell above should always match. If you are running the Notebooks locally and the versions do not match, please install the IQ# version that matches the version of the `Microsoft.Quantum.Katas` package.\n",
|
||||
"> <details>\n",
|
||||
"> <summary><u>How to install the right IQ# version</u></summary>\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.5.1904.1302, the installation steps are as follows:\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.6.1905.301, the installation steps are as follows:\n",
|
||||
">\n",
|
||||
"> 1. Stop the kernel.\n",
|
||||
"> 2. Uninstall the existing version of IQ#:\n",
|
||||
"> dotnet tool uninstall microsoft.quantum.iqsharp -g\n",
|
||||
"> 3. Install the matching version:\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.5.1904.1302\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.6.1905.301\n",
|
||||
"> 4. Reinstall the kernel:\n",
|
||||
"> dotnet iqsharp install\n",
|
||||
"> 5. Restart the Notebook.\n",
|
||||
|
@ -94,17 +94,12 @@
|
|||
"source": [
|
||||
"%kata T11_StateFlip_Test \n",
|
||||
"\n",
|
||||
"operation StateFlip (q : Qubit) : Unit {\n",
|
||||
"operation StateFlip (q : Qubit) : Unit is Adj {\n",
|
||||
" // The Pauli X gate will change the |0⟩ state to the |1⟩ state and vice versa.\n",
|
||||
" // Type X(q);\n",
|
||||
" // Then run the cell using Ctrl/⌘+Enter.\n",
|
||||
"\n",
|
||||
" body (...) {\n",
|
||||
" // The Pauli X gate will change the |0⟩ state to the |1⟩ state and vice versa.\n",
|
||||
" // Type X(q);\n",
|
||||
" // Then run the cell using Ctrl/⌘+Enter.\n",
|
||||
"\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" adjoint self;\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
|
@ -134,13 +129,8 @@
|
|||
"source": [
|
||||
"%kata T12_BasisChange_Test \n",
|
||||
"\n",
|
||||
"operation BasisChange (q : Qubit) : Unit {\n",
|
||||
" \n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" adjoint self;\n",
|
||||
"operation BasisChange (q : Qubit) : Unit is Adj {\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
|
@ -163,13 +153,8 @@
|
|||
"source": [
|
||||
"%kata T13_SignFlip_Test \n",
|
||||
"\n",
|
||||
"operation SignFlip (q : Qubit) : Unit {\n",
|
||||
"\n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" adjoint self;\n",
|
||||
"operation SignFlip (q : Qubit) : Unit is Adj {\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
|
@ -190,7 +175,7 @@
|
|||
"- If the qubit is in superposition, change its state according to the effect on basis vectors.\n",
|
||||
"\n",
|
||||
"> This is the first operation in this kata that is not self-adjoint, i.e., applying it for a second time\n",
|
||||
"> does not return the qubit to the original state. `adjoint invert` means that Q# can compute the operation \n",
|
||||
"> does not return the qubit to the original state. `is Adj` means that Q# can compute the operation \n",
|
||||
"> that returns the qubit to the original state automatically."
|
||||
]
|
||||
},
|
||||
|
@ -202,13 +187,8 @@
|
|||
"source": [
|
||||
"%kata T14_AmplitudeChange_Test\n",
|
||||
"\n",
|
||||
"operation AmplitudeChange (q : Qubit, α : Double) : Unit {\n",
|
||||
"\n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" adjoint invert;\n",
|
||||
"operation AmplitudeChange (q : Qubit, α : Double) : Unit is Adj {\n",
|
||||
" // ...\n",
|
||||
"}\n"
|
||||
]
|
||||
},
|
||||
|
@ -231,13 +211,8 @@
|
|||
"source": [
|
||||
"%kata T15_PhaseFlip_Test\n",
|
||||
"\n",
|
||||
"operation PhaseFlip (q : Qubit) : Unit {\n",
|
||||
" \n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" adjoint invert;\n",
|
||||
"operation PhaseFlip (q : Qubit) : Unit is Adj { \n",
|
||||
" // ...\n",
|
||||
"}\n",
|
||||
"\n"
|
||||
]
|
||||
|
@ -267,13 +242,8 @@
|
|||
"source": [
|
||||
"%kata T16_PhaseChange_Test\n",
|
||||
"\n",
|
||||
"operation PhaseChange (q : Qubit, α : Double) : Unit {\n",
|
||||
" \n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" adjoint invert;\n",
|
||||
"operation PhaseChange (q : Qubit, α : Double) : Unit is Adj {\n",
|
||||
" // ...\n",
|
||||
"}\n"
|
||||
]
|
||||
},
|
||||
|
@ -296,13 +266,9 @@
|
|||
"source": [
|
||||
"%kata T17_BellStateChange1_Test\n",
|
||||
"\n",
|
||||
"operation BellStateChange1 (qs : Qubit[]) : Unit {\n",
|
||||
"operation BellStateChange1 (qs : Qubit[]) : Unit is Adj {\n",
|
||||
" \n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" adjoint invert;\n",
|
||||
" // ...\n",
|
||||
"}\n"
|
||||
]
|
||||
},
|
||||
|
@ -325,13 +291,9 @@
|
|||
"source": [
|
||||
"%kata T18_BellStateChange2_Test\n",
|
||||
"\n",
|
||||
"operation BellStateChange2 (qs : Qubit[]) : Unit {\n",
|
||||
"operation BellStateChange2 (qs : Qubit[]) : Unit is Adj {\n",
|
||||
" \n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" adjoint invert;\n",
|
||||
" // ...\n",
|
||||
"}\n"
|
||||
]
|
||||
},
|
||||
|
@ -354,13 +316,9 @@
|
|||
"source": [
|
||||
"%kata T19_BellStateChange3_Test\n",
|
||||
"\n",
|
||||
"operation BellStateChange3 (qs : Qubit[]) : Unit {\n",
|
||||
"operation BellStateChange3 (qs : Qubit[]) : Unit is Adj {\n",
|
||||
" \n",
|
||||
" body (...) {\n",
|
||||
" // ...\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" adjoint invert;\n",
|
||||
" // ...\n",
|
||||
"}\n"
|
||||
]
|
||||
},
|
||||
|
@ -451,7 +409,7 @@
|
|||
"\n",
|
||||
"**Goal:** Change the two-qubit state to $\\alpha |00\\rangle + \\color{red}\\gamma |01\\rangle + \\color{red}\\beta |10\\rangle + \\delta |11\\rangle$.\n",
|
||||
"\n",
|
||||
"> This task can be solved using one primitive gate; as an exercise, try to express the solution using several (possibly controlled) Pauli gates."
|
||||
"> This task can be solved using one intrinsic gate; as an exercise, try to express the solution using several (possibly controlled) Pauli gates."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Quantum.Kata.BasicGates {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -72,27 +72,19 @@ namespace Quantum.Kata.BasicGates {
|
|||
// If the qubit is in state |0⟩, change its state to cos(alpha)*|0⟩ + sin(alpha)*|1⟩.
|
||||
// If the qubit is in state |1⟩, change its state to -sin(alpha)*|0⟩ + cos(alpha)*|1⟩.
|
||||
// If the qubit is in superposition, change its state according to the effect on basis vectors.
|
||||
operation AmplitudeChange_Reference (q : Qubit, alpha : Double) : Unit {
|
||||
|
||||
body (...) {
|
||||
Ry(2.0 * alpha, q);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation AmplitudeChange_Reference (q : Qubit, alpha : Double) : Unit
|
||||
is Adj {
|
||||
Ry(2.0 * alpha, q);
|
||||
}
|
||||
|
||||
|
||||
// Task 1.5. Phase flip
|
||||
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
|
||||
// Goal: Change the qubit state to α |0⟩ + iβ |1⟩ (flip the phase of |1⟩ component of the superposition).
|
||||
operation PhaseFlip_Reference (q : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
S(q);
|
||||
// alternatively Rz(0.5 * PI(), q);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation PhaseFlip_Reference (q : Qubit) : Unit
|
||||
is Adj {
|
||||
S(q);
|
||||
// alternatively Rz(0.5 * PI(), q);
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,54 +96,38 @@ namespace Quantum.Kata.BasicGates {
|
|||
// If the qubit is in state |0⟩, don't change its state.
|
||||
// If the qubit is in state |1⟩, change its state to exp(i*alpha)|1⟩.
|
||||
// If the qubit is in superposition, change its state according to the effect on basis vectors.
|
||||
operation PhaseChange_Reference (q : Qubit, alpha : Double) : Unit {
|
||||
|
||||
body (...) {
|
||||
Rz(alpha, q);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation PhaseChange_Reference (q : Qubit, alpha : Double) : Unit
|
||||
is Adj {
|
||||
Rz(alpha, q);
|
||||
}
|
||||
|
||||
|
||||
// Task 1.7. Bell state change - 1
|
||||
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
|
||||
// Goal: Change the two-qubit state to |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2).
|
||||
operation BellStateChange1_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
Z(qs[0]);
|
||||
// alternatively Z(qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BellStateChange1_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
Z(qs[0]);
|
||||
// alternatively Z(qs[1]);
|
||||
}
|
||||
|
||||
|
||||
// Task 1.8. Bell state change - 2
|
||||
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
|
||||
// Goal: Change the two-qubit state to |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2).
|
||||
operation BellStateChange2_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
X(qs[0]);
|
||||
// alternatively X(qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BellStateChange2_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
X(qs[0]);
|
||||
// alternatively X(qs[1]);
|
||||
}
|
||||
|
||||
|
||||
// Task 1.9. Bell state change - 3
|
||||
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
|
||||
// Goal: Change the two-qubit state to |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2).
|
||||
operation BellStateChange3_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
Y(qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BellStateChange3_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
Y(qs[0]);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Quantum.Kata.BasicGates {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -94,26 +94,18 @@ namespace Quantum.Kata.BasicGates {
|
|||
// If the qubit is in state |0⟩, change its state to cos(alpha)*|0⟩ + sin(alpha)*|1⟩.
|
||||
// If the qubit is in state |1⟩, change its state to -sin(alpha)*|0⟩ + cos(alpha)*|1⟩.
|
||||
// If the qubit is in superposition, change its state according to the effect on basis vectors.
|
||||
operation AmplitudeChange (q : Qubit, alpha : Double) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation AmplitudeChange (q : Qubit, alpha : Double) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 1.5. Phase flip
|
||||
// Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩.
|
||||
// Goal: Change the qubit state to α |0⟩ + iβ |1⟩ (flip the phase of |1⟩ component of the superposition).
|
||||
operation PhaseFlip (q : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation PhaseFlip (q : Qubit) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,52 +117,36 @@ namespace Quantum.Kata.BasicGates {
|
|||
// If the qubit is in state |0⟩, don't change its state.
|
||||
// If the qubit is in state |1⟩, change its state to exp(i*alpha)|1⟩.
|
||||
// If the qubit is in superposition, change its state according to the effect on basis vectors.
|
||||
operation PhaseChange (q : Qubit, alpha : Double) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation PhaseChange (q : Qubit, alpha : Double) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 1.7. Bell state change - 1
|
||||
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
|
||||
// Goal: Change the two-qubit state to |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2).
|
||||
operation BellStateChange1 (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BellStateChange1 (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 1.8. Bell state change - 2
|
||||
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
|
||||
// Goal: Change the two-qubit state to |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2).
|
||||
operation BellStateChange2 (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BellStateChange2 (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Task 1.9. Bell state change - 3
|
||||
// Input: Two entangled qubits in Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2).
|
||||
// Goal: Change the two-qubit state to |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2).
|
||||
operation BellStateChange3 (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BellStateChange3 (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,65 +9,59 @@
|
|||
|
||||
namespace Quantum.Kata.BasicGates {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// helper wrapper to represent operation on one qubit as an operation on an array of qubits
|
||||
operation ArrayWrapperOperation (op : (Qubit => Unit : Adjoint), qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
op(qs[0]);
|
||||
}
|
||||
|
||||
adjoint (...) {
|
||||
Adjoint op(qs[0]);
|
||||
}
|
||||
operation ArrayWrapperOperation (op : (Qubit => Unit is Adj), qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
op(qs[0]);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T11_StateFlip_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _), 1);
|
||||
AssertOperationsEqualReferenced(1, ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T12_BasisChange_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _), 1);
|
||||
AssertOperationsEqualReferenced(1, ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T13_SignFlip_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation(SignFlip, _), ArrayWrapperOperation(SignFlip_Reference, _), 1);
|
||||
AssertOperationsEqualReferenced(1, ArrayWrapperOperation(SignFlip, _), ArrayWrapperOperation(SignFlip_Reference, _));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T14_AmplitudeChange_Test () : Unit {
|
||||
for (i in 0 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation(AmplitudeChange(_, alpha), _), ArrayWrapperOperation(AmplitudeChange_Reference(_, alpha), _), 1);
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
AssertOperationsEqualReferenced(1, ArrayWrapperOperation(AmplitudeChange(_, alpha), _), ArrayWrapperOperation(AmplitudeChange_Reference(_, alpha), _));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T15_PhaseFlip_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseFlip, _), ArrayWrapperOperation(PhaseFlip_Reference, _), 1);
|
||||
AssertOperationsEqualReferenced(1, ArrayWrapperOperation(PhaseFlip, _), ArrayWrapperOperation(PhaseFlip_Reference, _));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T16_PhaseChange_Test () : Unit {
|
||||
for (i in 0 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseChange(_, alpha), _), ArrayWrapperOperation(PhaseChange_Reference(_, alpha), _), 1);
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
AssertOperationsEqualReferenced(1, ArrayWrapperOperation(PhaseChange(_, alpha), _), ArrayWrapperOperation(PhaseChange_Reference(_, alpha), _));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,24 +71,21 @@ namespace Quantum.Kata.BasicGates {
|
|||
// 1 - |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
|
||||
// 2 - |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
|
||||
// 3 - |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
|
||||
operation StatePrep_BellState (qs : Qubit[], state : Int) : Unit {
|
||||
operation StatePrep_BellState (qs : Qubit[], state : Int) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
|
||||
// now we have |00⟩ + |11⟩ - modify it based on state arg
|
||||
if (state % 2 == 1) {
|
||||
// negative phase
|
||||
Z(qs[1]);
|
||||
}
|
||||
|
||||
if (state / 2 == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
// now we have |00⟩ + |11⟩ - modify it based on state arg
|
||||
if (state % 2 == 1) {
|
||||
// negative phase
|
||||
Z(qs[1]);
|
||||
}
|
||||
|
||||
if (state / 2 == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -153,7 +144,7 @@ namespace Quantum.Kata.BasicGates {
|
|||
// we need to create an input state |A⟩ and check that the output state is correct
|
||||
using (qs = Qubit[2]) {
|
||||
for (i in 0 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
|
||||
// prepare A state
|
||||
StatePrep_A(alpha, qs[0]);
|
||||
|
@ -215,20 +206,20 @@ namespace Quantum.Kata.BasicGates {
|
|||
|
||||
|
||||
operation T23_TwoQubitGate3_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(SwapWrapper, TwoQubitGate3_Reference, 2);
|
||||
AssertOperationsEqualReferenced(TwoQubitGate3, TwoQubitGate3_Reference, 2);
|
||||
AssertOperationsEqualReferenced(2, SwapWrapper, TwoQubitGate3_Reference);
|
||||
AssertOperationsEqualReferenced(2, TwoQubitGate3, TwoQubitGate3_Reference);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T24_ToffoliGate_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(ToffoliGate, ToffoliGate_Reference, 3);
|
||||
AssertOperationsEqualReferenced(3, ToffoliGate, ToffoliGate_Reference);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T25_FredkinGate_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(FredkinGate, FredkinGate_Reference, 3);
|
||||
AssertOperationsEqualReferenced(3, FredkinGate, FredkinGate_Reference);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -43,35 +43,26 @@ namespace Quantum.Kata.CHSHGame {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. Entangled pair
|
||||
operation CreateEntangledPair_Reference (qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation CreateEntangledPair_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
}
|
||||
|
||||
|
||||
// Task 2.2. Alice's quantum strategy
|
||||
operation AliceQuantum_Reference (bit : Bool, qubit : Qubit) : Bool {
|
||||
if (bit) {
|
||||
// Measure in sign basis if bit is 1
|
||||
return BoolFromResult(Measure([PauliX], [qubit]));
|
||||
} else {
|
||||
// Measure in computational basis if bit is 0
|
||||
return BoolFromResult(Measure([PauliZ], [qubit]));
|
||||
}
|
||||
// Measure in sign basis if bit is 1, and
|
||||
// measure in computational basis if bit is 0
|
||||
let basis = bit ? PauliX | PauliZ;
|
||||
return BoolFromResult(Measure([basis], [qubit]));
|
||||
}
|
||||
|
||||
|
||||
// Task 2.3. Rotate Bob's qubit
|
||||
operation RotateBobQubit_Reference (clockwise : Bool, qubit : Qubit) : Unit {
|
||||
if (clockwise) {
|
||||
Ry(-2.0 * PI() / 8.0, qubit);
|
||||
} else {
|
||||
Ry(2.0 * PI() / 8.0, qubit);
|
||||
}
|
||||
let angle = 2.0 * PI() / 8.0;
|
||||
Ry(clockwise ? -angle | angle, qubit);
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,20 +76,18 @@ namespace Quantum.Kata.CHSHGame {
|
|||
// Task 2.5. Play the CHSH game
|
||||
operation PlayQuantumCHSH_Reference (askAlice : (Qubit => Bool),
|
||||
askBob : (Qubit => Bool)) : (Bool, Bool) {
|
||||
mutable aliceResult = false;
|
||||
mutable bobResult = false;
|
||||
|
||||
using ((aliceQubit, bobQubit) = (Qubit(), Qubit())) {
|
||||
CreateEntangledPair_Reference([aliceQubit, bobQubit]);
|
||||
|
||||
set aliceResult = askAlice(aliceQubit);
|
||||
set bobResult = askBob(bobQubit);
|
||||
let aliceResult = askAlice(aliceQubit);
|
||||
let bobResult = askBob(bobQubit);
|
||||
|
||||
Reset(aliceQubit);
|
||||
Reset(bobQubit);
|
||||
return (aliceResult, bobResult);
|
||||
}
|
||||
|
||||
return (aliceResult, bobResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace Quantum.Kata.CHSHGame {
|
||||
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
|
@ -75,7 +76,7 @@ namespace Quantum.Kata.CHSHGame {
|
|||
operation CreateEntangledPair (qs : Qubit[]) : Unit {
|
||||
// The following lines enforce the constraints on the input that you are given.
|
||||
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
EqualityFactI(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
|
||||
// ...
|
||||
fail "Task 2.1 not implemented yet";
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
|
||||
namespace Quantum.Kata.CHSHGame {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
operation T11_WinCondition_Test () : Unit {
|
||||
for (i in 0..1 <<< 4 - 1) {
|
||||
let bits = BoolArrFromPositiveInt(i, 4);
|
||||
AssertBoolEqual(
|
||||
EqualityFactB(
|
||||
WinCondition(bits[0], bits[1], bits[2], bits[3]),
|
||||
(bits[0] and bits[1]) == (bits[2] != bits[3]),
|
||||
$"Win condition is wrong for X = {bits[0]}, Y = {bits[1]}, A = {bits[2]}, " +
|
||||
|
@ -38,16 +38,16 @@ namespace Quantum.Kata.CHSHGame {
|
|||
set wins = wins + 1;
|
||||
}
|
||||
}
|
||||
Message($"Win rate {ToDouble(wins) / 1000.}");
|
||||
Message($"Win rate {IntAsDouble(wins) / 1000.}");
|
||||
|
||||
AssertBoolEqual(wins >= 700, true,
|
||||
EqualityFactB(wins >= 700, true,
|
||||
"Alice and Bob's classical strategy is not optimal");
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation AssertEqualOnZeroState (N : Int, taskImpl : (Qubit[] => Unit),
|
||||
refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
refImpl : (Qubit[] => Unit is Adj)) : Unit {
|
||||
using (qs = Qubit[N]) {
|
||||
// apply operation that needs to be tested
|
||||
taskImpl(qs);
|
||||
|
@ -70,20 +70,20 @@ namespace Quantum.Kata.CHSHGame {
|
|||
// ------------------------------------------------------
|
||||
operation T22_AliceQuantum_Test () : Unit {
|
||||
using (q = Qubit()) {
|
||||
AssertBoolEqual(AliceQuantum(false, q), false, "|0⟩ not measured as false");
|
||||
EqualityFactB(AliceQuantum(false, q), false, "|0⟩ not measured as false");
|
||||
Reset(q);
|
||||
|
||||
X(q);
|
||||
AssertBoolEqual(AliceQuantum(false, q), true, "|1⟩ not measured as true");
|
||||
EqualityFactB(AliceQuantum(false, q), true, "|1⟩ not measured as true");
|
||||
Reset(q);
|
||||
|
||||
H(q);
|
||||
AssertBoolEqual(AliceQuantum(true, q), false, "|+⟩ is not measured as false");
|
||||
EqualityFactB(AliceQuantum(true, q), false, "|+⟩ is not measured as false");
|
||||
Reset(q);
|
||||
|
||||
X(q);
|
||||
H(q);
|
||||
AssertBoolEqual(AliceQuantum(true, q), true, "|-⟩ is not measured as true");
|
||||
EqualityFactB(AliceQuantum(true, q), true, "|-⟩ is not measured as true");
|
||||
Reset(q);
|
||||
}
|
||||
}
|
||||
|
@ -94,18 +94,16 @@ namespace Quantum.Kata.CHSHGame {
|
|||
op(qs[0]);
|
||||
}
|
||||
|
||||
operation QubitToRegisterOperationA (op : (Qubit => Unit : Adjoint), qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
op(qs[0]);
|
||||
}
|
||||
adjoint auto;
|
||||
operation QubitToRegisterOperationA (op : (Qubit => Unit is Adj), qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
op(qs[0]);
|
||||
}
|
||||
|
||||
operation T23_RotateBobQubit_Test () : Unit {
|
||||
AssertOperationsEqualReferenced(QubitToRegisterOperation(RotateBobQubit(true, _), _),
|
||||
QubitToRegisterOperationA(Ry(-2.0 * PI() / 8.0, _), _), 1);
|
||||
AssertOperationsEqualReferenced(QubitToRegisterOperation(RotateBobQubit(false, _), _),
|
||||
QubitToRegisterOperationA(Ry(2.0 * PI() / 8.0, _), _), 1);
|
||||
AssertOperationsEqualReferenced(1, QubitToRegisterOperation(RotateBobQubit(true, _), _),
|
||||
QubitToRegisterOperationA(Ry(-2.0 * PI() / 8.0, _), _));
|
||||
AssertOperationsEqualReferenced(1, QubitToRegisterOperation(RotateBobQubit(false, _), _),
|
||||
QubitToRegisterOperationA(Ry(2.0 * PI() / 8.0, _), _));
|
||||
}
|
||||
|
||||
|
||||
|
@ -113,21 +111,21 @@ namespace Quantum.Kata.CHSHGame {
|
|||
operation T24_BobQuantum_Test () : Unit {
|
||||
using (q = Qubit()) {
|
||||
RotateBobQubit_Reference(false, q);
|
||||
AssertBoolEqual(BobQuantum(false, q), false, "π/8 from |0⟩ not measured as false");
|
||||
EqualityFactB(BobQuantum(false, q), false, "π/8 from |0⟩ not measured as false");
|
||||
Reset(q);
|
||||
|
||||
X(q);
|
||||
RotateBobQubit_Reference(false, q);
|
||||
AssertBoolEqual(BobQuantum(false, q), true, "π/8 from |1⟩ not measured as true");
|
||||
EqualityFactB(BobQuantum(false, q), true, "π/8 from |1⟩ not measured as true");
|
||||
Reset(q);
|
||||
|
||||
RotateBobQubit_Reference(true, q);
|
||||
AssertBoolEqual(BobQuantum(true, q), false, "-π/8 from |0⟩ not measured as false");
|
||||
EqualityFactB(BobQuantum(true, q), false, "-π/8 from |0⟩ not measured as false");
|
||||
Reset(q);
|
||||
|
||||
X(q);
|
||||
RotateBobQubit_Reference(true, q);
|
||||
AssertBoolEqual(BobQuantum(true, q), true, "-π/8 from |1⟩ not measured as true");
|
||||
EqualityFactB(BobQuantum(true, q), true, "-π/8 from |1⟩ not measured as true");
|
||||
Reset(q);
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +142,7 @@ namespace Quantum.Kata.CHSHGame {
|
|||
set wins = wins + 1;
|
||||
}
|
||||
}
|
||||
AssertAlmostEqualTol(ToDouble(wins) / 10000., 0.85, 0.01);
|
||||
EqualityWithinToleranceFact(IntAsDouble(wins) / 10000., 0.85, 0.01);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%package Microsoft.Quantum.Katas::0.5.1904.1302"
|
||||
"%package Microsoft.Quantum.Katas::0.6.1905.301"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -44,13 +44,13 @@
|
|||
"> The package versions in the output of the cell above should always match. If you are running the Notebooks locally and the versions do not match, please install the IQ# version that matches the version of the `Microsoft.Quantum.Katas` package.\n",
|
||||
"> <details>\n",
|
||||
"> <summary><u>How to install the right IQ# version</u></summary>\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.5.1904.1302, the installation steps are as follows:\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.6.1905.301, the installation steps are as follows:\n",
|
||||
">\n",
|
||||
"> 1. Stop the kernel.\n",
|
||||
"> 2. Uninstall the existing version of IQ#:\n",
|
||||
"> dotnet tool uninstall microsoft.quantum.iqsharp -g\n",
|
||||
"> 3. Install the matching version:\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.5.1904.1302\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.6.1905.301\n",
|
||||
"> 4. Reinstall the kernel:\n",
|
||||
"> dotnet iqsharp install\n",
|
||||
"> 5. Restart the Notebook.\n",
|
||||
|
@ -169,10 +169,12 @@
|
|||
"source": [
|
||||
"%kata T13_Oracle_Kth_Qubit_Test \n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Diagnostics;\n",
|
||||
"\n",
|
||||
"operation Oracle_Kth_Qubit (x : Qubit[], y : Qubit, k : Int) : Unit {\n",
|
||||
" // The following line enforces the constraints on the value of k that you are given.\n",
|
||||
" // You don't need to modify it. Feel free to remove it, this won't cause your code to fail.\n",
|
||||
" AssertBoolEqual(0 <= k and k < Length(x), true, \"k should be between 0 and N-1, inclusive\");\n",
|
||||
" EqualityFactB(0 <= k and k < Length(x), true, \"k should be between 0 and N-1, inclusive\");\n",
|
||||
"\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
|
@ -234,10 +236,12 @@
|
|||
"source": [
|
||||
"%kata T15_Oracle_ProductFunction_Test\n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Diagnostics;\n",
|
||||
"\n",
|
||||
"operation Oracle_ProductFunction (x : Qubit[], y : Qubit, r : Int[]) : Unit {\n",
|
||||
" // The following line enforces the constraint on the input arrays.\n",
|
||||
" // You don't need to modify it. Feel free to remove it, this won't cause your code to fail.\n",
|
||||
" AssertIntEqual(Length(x), Length(r), \"Arrays should have the same length\");\n",
|
||||
" EqualityFactI(Length(x), Length(r), \"Arrays should have the same length\");\n",
|
||||
"\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
|
@ -272,10 +276,12 @@
|
|||
"source": [
|
||||
"%kata T16_Oracle_ProductWithNegationFunction_Test\n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Diagnostics;\n",
|
||||
"\n",
|
||||
"operation Oracle_ProductWithNegationFunction (x : Qubit[], y : Qubit, r : Int[]) : Unit {\n",
|
||||
" // The following line enforces the constraint on the input arrays.\n",
|
||||
" // You don't need to modify it. Feel free to remove it, this won't cause your code to fail.\n",
|
||||
" AssertIntEqual(Length(x), Length(r), \"Arrays should have the same length\");\n",
|
||||
" EqualityFactI(Length(x), Length(r), \"Arrays should have the same length\");\n",
|
||||
"\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
|
@ -311,11 +317,13 @@
|
|||
"source": [
|
||||
"%kata T17_Oracle_HammingWithPrefix_Test\n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Diagnostics;\n",
|
||||
"\n",
|
||||
"operation Oracle_HammingWithPrefix (x : Qubit[], y : Qubit, prefix : Int[]) : Unit {\n",
|
||||
" // The following line enforces the constraint on the input arrays.\n",
|
||||
" // You don't need to modify it. Feel free to remove it, this won't cause your code to fail.\n",
|
||||
" let K = Length(prefix);\n",
|
||||
" AssertBoolEqual(1 <= K and K <= Length(x), true, \"K should be between 1 and N, inclusive\");\n",
|
||||
" EqualityFactB(1 <= K and K <= Length(x), true, \"K should be between 1 and N, inclusive\");\n",
|
||||
"\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
|
@ -349,10 +357,12 @@
|
|||
"source": [
|
||||
"%kata T18_Oracle_MajorityFunction_Test\n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Diagnostics;\n",
|
||||
"\n",
|
||||
"operation Oracle_MajorityFunction (x : Qubit[], y : Qubit) : Unit {\n",
|
||||
" // The following line enforces the constraint on the input array.\n",
|
||||
" // You don't need to modify it. Feel free to remove it, this won't cause your code to fail.\n",
|
||||
" AssertBoolEqual(3 == Length(x), true, \"x should have exactly 3 qubits\");\n",
|
||||
" EqualityFactI(3, Length(x), \"x should have exactly 3 qubits\");\n",
|
||||
"\n",
|
||||
" // ...\n",
|
||||
"}"
|
||||
|
@ -446,9 +456,11 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"open Microsoft.Quantum.Diagnostics;\n",
|
||||
"\n",
|
||||
"operation Run_DeutschJozsa_Algorithm () : String {\n",
|
||||
" // You can use AssertBoolEqual function to assert that the return value of DJ_Algorithm operation matches the expected value\n",
|
||||
" AssertBoolEqual(DJ_Algorithm(4, Oracle_Zero), true, \"f(x) = 0 not identified as constant\");\n",
|
||||
" // You can use EqualityFactB function to represent the invariant that the return value of DJ_Algorithm operation matches the expected value\n",
|
||||
" EqualityFactB(DJ_Algorithm(4, Oracle_Zero), true, \"f(x) = 0 not identified as constant\");\n",
|
||||
" \n",
|
||||
" // Run the algorithm for the rest of the oracles\n",
|
||||
" // ...\n",
|
||||
|
@ -532,20 +544,20 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// Start by implementing a function AreIntArraysEqual \n",
|
||||
"// Start by implementing a function AllEqualityFactI \n",
|
||||
"// to check the results of applying the algorithm to each oracle in a uniform manner.\n",
|
||||
"function AreIntArraysEqual(actual : Int[], expected : Int[]) : Bool {\n",
|
||||
"function AllEqualityFactI(actual : Int[], expected : Int[]) : Bool {\n",
|
||||
" // Check that array lengths are equal\n",
|
||||
" // ...\n",
|
||||
" \n",
|
||||
" // Check that the corresponding elements of the arrays are equal\n",
|
||||
" // ...\n",
|
||||
" fail \"AreIntArraysEqual is not implemented\";\n",
|
||||
" fail \"AllEqualityFactI is not implemented\";\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"operation Run_BernsteinVazirani_Algorithm () : String {\n",
|
||||
" // Now use AreIntArraysEqual to verify the results of the algorithm\n",
|
||||
" if (not AreIntArraysEqual(BV_Algorithm(3, Oracle_Zero), [0, 0, 0])) {\n",
|
||||
" // Now use AllEqualityFactI to verify the results of the algorithm\n",
|
||||
" if (not AllEqualityFactI(BV_Algorithm(3, Oracle_Zero), [0, 0, 0])) {\n",
|
||||
" return \"Incorrect result for f(x) = 0\";\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
|
||||
namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -23,15 +25,11 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 1) N qubits in arbitrary state |x⟩ (input register)
|
||||
// 2) a qubit in arbitrary state |y⟩ (output qubit)
|
||||
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_Zero_Reference (x : Qubit[], y : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// Since f(x) = 0 for all values of x, |y ⊕ f(x)⟩ = |y⟩.
|
||||
// This means that the operation doesn't need to do any transformation to the inputs.
|
||||
// Build the project and run the tests to see that T01_Oracle_Zero_Test test passes.
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_Zero_Reference (x : Qubit[], y : Qubit) : Unit
|
||||
is Adj {
|
||||
// Since f(x) = 0 for all values of x, |y ⊕ f(x)⟩ = |y⟩.
|
||||
// This means that the operation doesn't need to do any transformation to the inputs.
|
||||
// Build the project and run the tests to see that T01_Oracle_Zero_Test test passes.
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,15 +38,11 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 1) N qubits in arbitrary state |x⟩ (input register)
|
||||
// 2) a qubit in arbitrary state |y⟩ (output qubit)
|
||||
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_One_Reference (x : Qubit[], y : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// Since f(x) = 1 for all values of x, |y ⊕ f(x)⟩ = |y ⊕ 1⟩ = |NOT y⟩.
|
||||
// This means that the operation needs to flip qubit y (i.e. transform |0⟩ to |1⟩ and vice versa).
|
||||
X(y);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_One_Reference (x : Qubit[], y : Qubit) : Unit
|
||||
is Adj {
|
||||
// Since f(x) = 1 for all values of x, |y ⊕ f(x)⟩ = |y ⊕ 1⟩ = |NOT y⟩.
|
||||
// This means that the operation needs to flip qubit y (i.e. transform |0⟩ to |1⟩ and vice versa).
|
||||
X(y);
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,14 +52,10 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 2) a qubit in arbitrary state |y⟩ (output qubit)
|
||||
// 3) 0-based index of the qubit from input register (0 <= k < N)
|
||||
// Goal: transform state |x, y⟩ into state |x, y ⊕ xₖ⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_Kth_Qubit_Reference (x : Qubit[], y : Qubit, k : Int) : Unit {
|
||||
|
||||
body (...) {
|
||||
AssertBoolEqual(0 <= k and k < Length(x), true, "k should be between 0 and N-1, inclusive");
|
||||
CNOT(x[k], y);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_Kth_Qubit_Reference (x : Qubit[], y : Qubit, k : Int) : Unit
|
||||
is Adj {
|
||||
EqualityFactB(0 <= k and k < Length(x), true, "k should be between 0 and N-1, inclusive");
|
||||
CNOT(x[k], y);
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,17 +64,13 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 1) N qubits in arbitrary state |x⟩ (input register)
|
||||
// 2) a qubit in arbitrary state |y⟩ (output qubit)
|
||||
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_OddNumberOfOnes_Reference (x : Qubit[], y : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// Hint: f(x) can be represented as x_0 ⊕ x_1 ⊕ ... ⊕ x_(N-1)
|
||||
for (i in 0 .. Length(x) - 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
// alternative solution: ApplyToEachA(CNOT(_, y), x);
|
||||
operation Oracle_OddNumberOfOnes_Reference (x : Qubit[], y : Qubit) : Unit
|
||||
is Adj {
|
||||
// Hint: f(x) can be represented as x_0 ⊕ x_1 ⊕ ... ⊕ x_(N-1)
|
||||
for (q in x) {
|
||||
CNOT(q, y);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// alternative solution: ApplyToEachA(CNOT(_, y), x);
|
||||
}
|
||||
|
||||
|
||||
|
@ -97,21 +83,17 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
|
||||
|
||||
// Note: the functions featured in tasks 1.1, 1.3 and 1.4 are special cases of this function.
|
||||
operation Oracle_ProductFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
|
||||
operation Oracle_ProductFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : Unit
|
||||
is Adj {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
EqualityFactI(Length(x), Length(r), "Arrays should have the same length");
|
||||
|
||||
for (i in 0 .. Length(x) - 1) {
|
||||
if (r[i] == 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
for (i in IndexRange(x)) {
|
||||
if (r[i] == 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,26 +104,22 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 3) a bit vector of length N represented as Int[]
|
||||
// You are guaranteed that the qubit array and the bit vector have the same length.
|
||||
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_ProductWithNegationFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
|
||||
operation Oracle_ProductWithNegationFunction_Reference (x : Qubit[], y : Qubit, r : Int[]) : Unit
|
||||
is Adj {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
EqualityFactI(Length(x), Length(r), "Arrays should have the same length");
|
||||
|
||||
for (i in 0 .. Length(x) - 1) {
|
||||
if (r[i] == 1) {
|
||||
CNOT(x[i], y);
|
||||
} else {
|
||||
// do a 0-controlled NOT
|
||||
X(x[i]);
|
||||
CNOT(x[i], y);
|
||||
X(x[i]);
|
||||
}
|
||||
for (i in IndexRange(x)) {
|
||||
if (r[i] == 1) {
|
||||
CNOT(x[i], y);
|
||||
} else {
|
||||
// do a 0-controlled NOT
|
||||
X(x[i]);
|
||||
CNOT(x[i], y);
|
||||
X(x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,40 +132,36 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
// A prefix of length k of a state |x⟩ = |x₁, ..., xₙ⟩ is the state of its first k qubits |x₁, ..., xₖ⟩.
|
||||
// For example, a prefix of length 2 of a state |0110⟩ is 01.
|
||||
operation Oracle_HammingWithPrefix_Reference (x : Qubit[], y : Qubit, prefix : Int[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
let P = Length(prefix);
|
||||
AssertBoolEqual(1 <= P and P <= Length(x), true, "P should be between 1 and N, inclusive");
|
||||
operation Oracle_HammingWithPrefix_Reference (x : Qubit[], y : Qubit, prefix : Int[]) : Unit
|
||||
is Adj {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
let P = Length(prefix);
|
||||
EqualityFactB(1 <= P and P <= Length(x), true, "P should be between 1 and N, inclusive");
|
||||
|
||||
// Hint: the first part of the function is the same as in task 1.4
|
||||
for (i in 0 .. Length(x) - 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
// Hint: the first part of the function is the same as in task 1.4
|
||||
for (q in x) {
|
||||
CNOT(q, y);
|
||||
}
|
||||
|
||||
// add check for prefix as a multicontrolled NOT
|
||||
// true bits of r correspond to 1-controls, false bits - to 0-controls
|
||||
for (i in 0 .. P - 1) {
|
||||
// add check for prefix as a multicontrolled NOT
|
||||
// true bits of r correspond to 1-controls, false bits - to 0-controls
|
||||
for (i in 0 .. P - 1) {
|
||||
|
||||
if (prefix[i] == 0) {
|
||||
X(x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Controlled X(x[0 .. P - 1], y);
|
||||
|
||||
// uncompute changes done to input register
|
||||
for (i in 0 .. P - 1) {
|
||||
|
||||
if (prefix[i] == 0) {
|
||||
X(x[i]);
|
||||
}
|
||||
if (prefix[i] == 0) {
|
||||
X(x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Controlled X(x[0 .. P - 1], y);
|
||||
|
||||
// uncompute changes done to input register
|
||||
for (i in 0 .. P - 1) {
|
||||
|
||||
if (prefix[i] == 0) {
|
||||
X(x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -196,20 +170,16 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 1) 3 qubits in arbitrary state |x⟩ (input register)
|
||||
// 2) a qubit in arbitrary state |y⟩ (output qubit)
|
||||
// Goal: transform state |x, y⟩ into state |x, y ⊕ f(x)⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_MajorityFunction_Reference (x : Qubit[], y : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// The following line enforces the constraint on the input array.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertBoolEqual(3 == Length(x), true, "x should have exactly 3 qubits");
|
||||
operation Oracle_MajorityFunction_Reference (x : Qubit[], y : Qubit) : Unit
|
||||
is Adj {
|
||||
// The following line enforces the constraint on the input array.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
EqualityFactB(3 == Length(x), true, "x should have exactly 3 qubits");
|
||||
|
||||
// Hint: represent f(x) in terms of AND and ⊕ operations
|
||||
CCNOT(x[0], x[1], y);
|
||||
CCNOT(x[0], x[2], y);
|
||||
CCNOT(x[1], x[2], y);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// Hint: represent f(x) in terms of AND and ⊕ operations
|
||||
CCNOT(x[0], x[1], y);
|
||||
CCNOT(x[0], x[2], y);
|
||||
CCNOT(x[1], x[2], y);
|
||||
}
|
||||
|
||||
|
||||
|
@ -225,15 +195,11 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 1) create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩ on query register
|
||||
// (i.e. state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N) )
|
||||
// 2) create |-⟩ state (|-⟩ = (|0⟩ - |1⟩) / sqrt(2)) on answer register
|
||||
operation BV_StatePrep_Reference (query : Qubit[], answer : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
ApplyToEachA(H, query);
|
||||
X(answer);
|
||||
H(answer);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BV_StatePrep_Reference (query : Qubit[], answer : Qubit) : Unit
|
||||
is Adj {
|
||||
ApplyToEachA(H, query);
|
||||
X(answer);
|
||||
H(answer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -252,9 +218,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// |10...0⟩|0⟩ = |10...0⟩|r₀⟩, |010...0⟩|0⟩ = |010...0⟩|r₁⟩ and so on.
|
||||
// Quantum computing allows to perform this task in just one call to the oracle; try to implement this algorithm.
|
||||
operation BV_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Int[] {
|
||||
|
||||
mutable r = new Int[N];
|
||||
|
||||
|
||||
// allocate N qubits for input register and 1 qubit for output
|
||||
using ((x, y) = (Qubit[N], Qubit())) {
|
||||
|
||||
|
@ -269,18 +233,18 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
// measure all qubits of the input register;
|
||||
// the result of each measurement is converted to an Int
|
||||
mutable r = new Int[N];
|
||||
for (i in 0 .. N - 1) {
|
||||
if (M(x[i]) != Zero) {
|
||||
set r[i] = 1;
|
||||
set r w/= i <- 1;
|
||||
}
|
||||
}
|
||||
|
||||
// before releasing the qubits make sure they are all in |0⟩ state
|
||||
ResetAll(x);
|
||||
Reset(y);
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
@ -339,11 +303,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// Output:
|
||||
// A bit vector r which generates the same oracle as the one you are given
|
||||
operation Noname_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Int[] {
|
||||
|
||||
// Declare a Bool array in which the result will be stored;
|
||||
// the array has to be mutable to allow updating its elements.
|
||||
mutable r = new Int[N];
|
||||
|
||||
|
||||
using ((x, y) = (Qubit[N], Qubit())) {
|
||||
// apply oracle to qubits in all 0 state
|
||||
Uf(x, y);
|
||||
|
@ -356,19 +316,22 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
// now y = Σᵢ 𝑟ᵢ
|
||||
|
||||
// Declare an Int array in which the result will be stored;
|
||||
// the variable has to be mutable to allow updating it.
|
||||
mutable r = new Int[N];
|
||||
|
||||
// measure the output register
|
||||
let m = M(y);
|
||||
if (m == One) {
|
||||
// adjust parity of bit vector r
|
||||
set r[0] = 1;
|
||||
set r w/= 0 <- 1;
|
||||
}
|
||||
|
||||
// before releasing the qubits make sure they are all in |0⟩ state
|
||||
ResetAll(x);
|
||||
Reset(y);
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -70,7 +71,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
operation Oracle_Kth_Qubit (x : Qubit[], y : Qubit, k : Int) : Unit {
|
||||
// The following line enforces the constraints on the value of k that you are given.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertBoolEqual(0 <= k and k < Length(x), true, "k should be between 0 and N-1, inclusive");
|
||||
EqualityFactB(0 <= k and k < Length(x), true, "k should be between 0 and N-1, inclusive");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
operation Oracle_ProductFunction (x : Qubit[], y : Qubit, r : Int[]) : Unit {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
|
||||
EqualityFactI(Length(x), Length(r), "Arrays should have the same length");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -116,7 +117,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
operation Oracle_ProductWithNegationFunction (x : Qubit[], y : Qubit, r : Int[]) : Unit {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(x), Length(r), "Arrays should have the same length");
|
||||
EqualityFactI(Length(x), Length(r), "Arrays should have the same length");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -135,7 +136,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
let P = Length(prefix);
|
||||
AssertBoolEqual(1 <= P and P <= Length(x), true, "P should be between 1 and N, inclusive");
|
||||
EqualityFactB(1 <= P and P <= Length(x), true, "P should be between 1 and N, inclusive");
|
||||
|
||||
// Hint: the first part of the function is the same as in task 1.4
|
||||
|
||||
|
@ -156,7 +157,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
operation Oracle_MajorityFunction (x : Qubit[], y : Qubit) : Unit {
|
||||
// The following line enforces the constraint on the input array.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertBoolEqual(3 == Length(x), true, "x should have exactly 3 qubits");
|
||||
EqualityFactB(3 == Length(x), true, "x should have exactly 3 qubits");
|
||||
|
||||
// Hint: represent f(x) in terms of AND and ⊕ operations
|
||||
|
||||
|
@ -176,13 +177,9 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// 1) create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩ on query register
|
||||
// (i.e. state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N) )
|
||||
// 2) create |-⟩ state (|-⟩ = (|0⟩ - |1⟩) / sqrt(2)) on answer register
|
||||
operation BV_StatePrep (query : Qubit[], answer : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
operation BV_StatePrep (query : Qubit[], answer : Qubit) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -203,7 +200,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
operation BV_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => Unit)) : Int[] {
|
||||
|
||||
// Declare an Int array in which the result will be stored;
|
||||
// the array has to be mutable to allow updating its elements.
|
||||
// the variable has to be mutable to allow updating it.
|
||||
mutable r = new Int[N];
|
||||
|
||||
// ...
|
||||
|
@ -226,7 +223,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// You might want to use something like the following:
|
||||
// let oracle = Oracle_ProductFunction(_, _, [...your bit vector here...]);
|
||||
|
||||
// Hint: use AssertIntArrayEqual function to assert that the return value of BV_Algorithm operation
|
||||
// Hint: use AllEqualityFactI function to assert that the return value of BV_Algorithm operation
|
||||
// matches the expected value (i.e. the bit vector passed to Oracle_ProductFunction).
|
||||
|
||||
// BV_Test appears in the list of unit tests for the solution; run it to verify your code.
|
||||
|
@ -278,7 +275,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// Hint: you will need to use partial application to test ones such as Oracle_Kth_Qubit and Oracle_ProductFunction;
|
||||
// see task 2.3 for a description of how to do that.
|
||||
|
||||
// Hint: use AssertBoolEqual function to assert that the return value of DJ_Algorithm operation matches the expected value
|
||||
// Hint: use EqualityFactB function to assert that the return value of DJ_Algorithm operation matches the expected value
|
||||
|
||||
// DJ_Test appears in the list of unit tests for the solution; run it to verify your code.
|
||||
|
||||
|
@ -306,7 +303,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// it just needs to produce equivalent results.
|
||||
|
||||
// Declare an Int array in which the result will be stored;
|
||||
// the array has to be mutable to allow updating its elements.
|
||||
// the variable has to be mutable to allow updating it.
|
||||
mutable r = new Int[N];
|
||||
|
||||
// ...
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
|
||||
namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
open Quantum.Kata.Utils;
|
||||
|
||||
|
@ -24,26 +25,22 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
|
||||
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
oracle(qs[0 .. N - 2], qs[N - 1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit is Adj)) : Unit
|
||||
is Adj {
|
||||
let N = Length(qs);
|
||||
oracle(qs[0 .. N - 2], qs[N - 1]);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation AssertTwoOraclesAreEqual (nQubits : Range,
|
||||
oracle1 : ((Qubit[], Qubit) => Unit),
|
||||
oracle2 : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
|
||||
oracle2 : ((Qubit[], Qubit) => Unit is Adj)) : Unit {
|
||||
let sol = ApplyOracle(_, oracle1);
|
||||
let refSol = ApplyOracleA(_, oracle2);
|
||||
|
||||
for (i in nQubits) {
|
||||
AssertOperationsEqualReferenced(sol, refSol, i + 1);
|
||||
AssertOperationsEqualReferenced(i + 1, sol, refSol);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,7 +82,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// ------------------------------------------------------
|
||||
operation AssertTwoOraclesWithIntAreEqual (r : Int[],
|
||||
oracle1 : ((Qubit[], Qubit, Int[]) => Unit),
|
||||
oracle2 : ((Qubit[], Qubit, Int[]) => Unit : Adjoint)) : Unit {
|
||||
oracle2 : ((Qubit[], Qubit, Int[]) => Unit is Adj)) : Unit {
|
||||
AssertTwoOraclesAreEqual(Length(r) .. Length(r), oracle1(_, _, r), oracle2(_, _, r));
|
||||
}
|
||||
|
||||
|
@ -102,7 +99,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
// the mask with all 0's corresponds to Oracle_Zero
|
||||
for (i in 0 .. L - 1) {
|
||||
set r[i] = 0;
|
||||
set r w/= i <- 0;
|
||||
}
|
||||
|
||||
for (i in 2 .. L) {
|
||||
|
@ -111,9 +108,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
// the mask with only the K-th element set to 1 corresponds to Oracle_Kth_Qubit
|
||||
for (i in 0 .. L - 1) {
|
||||
set r[i] = 1;
|
||||
AssertTwoOraclesAreEqual(L .. L, Oracle_ProductFunction(_, _, r), Oracle_Kth_Qubit_Reference(_, _, i));
|
||||
set r[i] = 0;
|
||||
AssertTwoOraclesAreEqual(L .. L, Oracle_ProductFunction(_, _, r w/ i <- 1), Oracle_Kth_Qubit_Reference(_, _, i));
|
||||
}
|
||||
|
||||
set r = [1, 0, 1, 0, 1, 0];
|
||||
|
@ -184,7 +179,7 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
function AssertIntArrayEqual (actual : Int[], expected : Int[], message : String) : Unit {
|
||||
function AllEqualityFactI (actual : Int[], expected : Int[], message : String) : Unit {
|
||||
|
||||
let n = Length(actual);
|
||||
if (n != Length(expected)) {
|
||||
|
@ -202,12 +197,12 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// ------------------------------------------------------
|
||||
function IntArrFromPositiveInt (n : Int, bits : Int) : Int[] {
|
||||
|
||||
let rbool = BoolArrFromPositiveInt(n, bits);
|
||||
let rbool = IntAsBoolArray(n, bits);
|
||||
mutable r = new Int[bits];
|
||||
|
||||
for (i in 0 .. bits - 1) {
|
||||
if (rbool[i]) {
|
||||
set r[i] = 1;
|
||||
set r w/= i <- 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,10 +213,10 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
// ------------------------------------------------------
|
||||
operation AssertBVAlgorithmWorks (r : Int[]) : Unit {
|
||||
let oracle = Oracle_ProductFunction_Reference(_, _, r);
|
||||
AssertIntArrayEqual(BV_Algorithm(Length(r), oracle), r, "Bernstein-Vazirani algorithm failed");
|
||||
AllEqualityFactI(BV_Algorithm(Length(r), oracle), r, "Bernstein-Vazirani algorithm failed");
|
||||
|
||||
let nu = GetOracleCallsCount(oracle);
|
||||
AssertBoolEqual(nu <= 1, true, $"You are allowed to call the oracle at most once, and you called it {nu} times");
|
||||
EqualityFactB(nu <= 1, true, $"You are allowed to call the oracle at most once, and you called it {nu} times");
|
||||
}
|
||||
|
||||
|
||||
|
@ -244,10 +239,10 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
// ------------------------------------------------------
|
||||
operation AssertDJAlgorithmWorks (N : Int, oracle : ((Qubit[], Qubit) => Unit), expected : Bool, msg : String) : Unit {
|
||||
AssertBoolEqual(DJ_Algorithm(N, oracle), expected, msg);
|
||||
EqualityFactB(DJ_Algorithm(N, oracle), expected, msg);
|
||||
|
||||
let nu = GetOracleCallsCount(oracle);
|
||||
AssertBoolEqual(nu <= 1, true, $"You are allowed to call the oracle at most once, and you called it {nu} times");
|
||||
EqualityFactB(nu <= 1, true, $"You are allowed to call the oracle at most once, and you called it {nu} times");
|
||||
}
|
||||
|
||||
|
||||
|
@ -284,11 +279,11 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
|
||||
// check that the oracle was called once (later it will be called again by test harness)
|
||||
let nu = GetOracleCallsCount(givenOracle);
|
||||
AssertBoolEqual(nu <= 1, true, $"You are allowed to call the oracle at most once, and you called it {nu} times");
|
||||
EqualityFactB(nu <= 1, true, $"You are allowed to call the oracle at most once, and you called it {nu} times");
|
||||
|
||||
// check that the oracle obtained from r
|
||||
// is equivalent to the oracle obtained from return value
|
||||
AssertIntEqual(Length(res), Length(r), "Returned bit vector must have the same length as the oracle input.");
|
||||
EqualityFactI(Length(res), Length(r), "Returned bit vector must have the same length as the oracle input.");
|
||||
let resOracle = Oracle_ProductWithNegationFunction_Reference(_, _, res);
|
||||
AssertTwoOraclesAreEqual(Length(r) .. Length(r), givenOracle, resOracle);
|
||||
}
|
||||
|
@ -318,3 +313,4 @@ namespace Quantum.Kata.DeutschJozsaAlgorithm {
|
|||
AssertNonameAlgorithmWorks([1, 0, 1, 0, 1, 0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ ENV PATH=$PATH:${HOME}/dotnet:${HOME}/.dotnet/tools \
|
|||
DOTNET_ROOT=${HOME}/dotnet
|
||||
|
||||
# install IQSharp
|
||||
RUN dotnet tool install -g Microsoft.Quantum.IQSharp --version 0.5.1904.1302
|
||||
RUN dotnet tool install -g Microsoft.Quantum.IQSharp --version 0.6.1905.301
|
||||
RUN dotnet iqsharp install --user --path-to-tool="$(which dotnet-iqsharp)"
|
||||
|
||||
# Make sure the contents of our repo are in ${HOME}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
namespace Quantum.Kata.GHZGame {
|
||||
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
@ -42,7 +42,7 @@ namespace Quantum.Kata.GHZGame {
|
|||
operation PlayClassicalGHZ_Reference (strategy : (Bool => Bool), inputs : Bool[]) : Bool[] {
|
||||
mutable results = new Bool[Length(inputs)];
|
||||
for (i in 0..Length(inputs) - 1) {
|
||||
set results[i] = strategy(inputs[i]);
|
||||
set results w/= i <- strategy(inputs[i]);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
@ -53,23 +53,21 @@ namespace Quantum.Kata.GHZGame {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. Entangled triple
|
||||
operation CreateEntangledTriple_Reference (qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
X(qs[0]);
|
||||
X(qs[1]);
|
||||
operation CreateEntangledTriple_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
X(qs[0]);
|
||||
X(qs[1]);
|
||||
|
||||
H(qs[0]);
|
||||
H(qs[1]);
|
||||
// At this point we have (|000⟩ - |010⟩ - |100⟩ + |110⟩) / 2
|
||||
H(qs[0]);
|
||||
H(qs[1]);
|
||||
// At this point we have (|000⟩ - |010⟩ - |100⟩ + |110⟩) / 2
|
||||
|
||||
// Flip the sign of the last term
|
||||
Controlled Z([qs[0]], qs[1]);
|
||||
// Flip the sign of the last term
|
||||
Controlled Z([qs[0]], qs[1]);
|
||||
|
||||
// Flip the state of the last qubit for the two middle terms
|
||||
(ControlledOnBitString([false, true], X))([qs[0], qs[1]], qs[2]);
|
||||
(ControlledOnBitString([true, false], X))([qs[0], qs[1]], qs[2]);
|
||||
}
|
||||
adjoint auto;
|
||||
// Flip the state of the last qubit for the two middle terms
|
||||
(ControlledOnBitString([false, true], X))([qs[0], qs[1]], qs[2]);
|
||||
(ControlledOnBitString([true, false], X))([qs[0], qs[1]], qs[2]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,19 +82,18 @@ namespace Quantum.Kata.GHZGame {
|
|||
|
||||
// Task 2.3. Play the GHZ game using the quantum strategy
|
||||
operation PlayQuantumGHZ_Reference (strategies : (Qubit => Bool)[]) : Bool[] {
|
||||
mutable abc = new Bool[3];
|
||||
|
||||
using (qs = Qubit[3]) {
|
||||
CreateEntangledTriple_Reference(qs);
|
||||
|
||||
|
||||
mutable abc = new Bool[3];
|
||||
for (i in 0..2) {
|
||||
set abc[i] = strategies[i](qs[i]);
|
||||
set abc w/= i <- strategies[i](qs[i]);
|
||||
}
|
||||
|
||||
ResetAll(qs);
|
||||
return abc;
|
||||
}
|
||||
|
||||
return abc;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
|
||||
namespace Quantum.Kata.GHZGame {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
// All possible starting bits (r, s and t) that the referee can give
|
||||
// to Alice, Bob and Charlie.
|
||||
|
@ -27,7 +28,7 @@ namespace Quantum.Kata.GHZGame {
|
|||
for (rst in RefereeBits()) {
|
||||
for (i in 0..1 <<< 3 - 1) {
|
||||
let abc = BoolArrFromPositiveInt(i, 3);
|
||||
AssertBoolEqual(
|
||||
EqualityFactB(
|
||||
WinCondition(rst, abc),
|
||||
WinCondition_Reference(rst, abc),
|
||||
$"Win condition is wrong for rst={rst}, abc={abc}");
|
||||
|
@ -47,17 +48,17 @@ namespace Quantum.Kata.GHZGame {
|
|||
set wins = wins + 1;
|
||||
}
|
||||
}
|
||||
return ToDouble(wins) / ToDouble(N);
|
||||
return IntAsDouble(wins) / IntAsDouble(N);
|
||||
}
|
||||
|
||||
operation T12_RandomClassical_Test () : Unit {
|
||||
AssertAlmostEqualTol(GetClassicalStrategySuccessRate(10000, RandomClassicalStrategy), 0.5, 0.02);
|
||||
EqualityWithinToleranceFact(GetClassicalStrategySuccessRate(10000, RandomClassicalStrategy), 0.5, 0.02);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T13_BestClassical_Test () : Unit {
|
||||
AssertAlmostEqualTol(GetClassicalStrategySuccessRate(10000, BestClassicalStrategy), 0.75, 0.02);
|
||||
EqualityWithinToleranceFact(GetClassicalStrategySuccessRate(10000, BestClassicalStrategy), 0.75, 0.02);
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,7 +75,7 @@ namespace Quantum.Kata.GHZGame {
|
|||
for (mode in 0..3) {
|
||||
let result = PlayClassicalGHZ(TestStrategy(_, mode), rst);
|
||||
let expected = PlayClassicalGHZ_Reference(TestStrategy(_, mode), rst);
|
||||
AssertBoolArrayEqual(result, expected, $"Unexpected result for rst={rst}");
|
||||
AllEqualityFactB(result, expected, $"Unexpected result for rst={rst}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +84,7 @@ namespace Quantum.Kata.GHZGame {
|
|||
// Part II. Quantum GHZ
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
operation AssertEqualOnZeroState (N : Int, taskImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
operation AssertEqualOnZeroState (N : Int, taskImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit is Adj)) : Unit {
|
||||
using (qs = Qubit[N]) {
|
||||
// apply operation that needs to be tested
|
||||
taskImpl(qs);
|
||||
|
@ -104,20 +105,20 @@ namespace Quantum.Kata.GHZGame {
|
|||
// ------------------------------------------------------
|
||||
operation T22_QuantumStrategy_Test () : Unit {
|
||||
using (q = Qubit()) {
|
||||
AssertBoolEqual(QuantumStrategy(false, q), false, "|0⟩ not measured as false");
|
||||
EqualityFactB(QuantumStrategy(false, q), false, "|0⟩ not measured as false");
|
||||
Reset(q);
|
||||
|
||||
X(q);
|
||||
AssertBoolEqual(QuantumStrategy(false, q), true, "|1⟩ not measured as true");
|
||||
EqualityFactB(QuantumStrategy(false, q), true, "|1⟩ not measured as true");
|
||||
Reset(q);
|
||||
|
||||
H(q);
|
||||
AssertBoolEqual(QuantumStrategy(true, q), false, "|+⟩ is not measured as false");
|
||||
EqualityFactB(QuantumStrategy(true, q), false, "|+⟩ is not measured as false");
|
||||
Reset(q);
|
||||
|
||||
X(q);
|
||||
H(q);
|
||||
AssertBoolEqual(QuantumStrategy(true, q), true, "|-⟩ is not measured as true");
|
||||
EqualityFactB(QuantumStrategy(true, q), true, "|-⟩ is not measured as true");
|
||||
Reset(q);
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ namespace Quantum.Kata.GHZGame {
|
|||
let rst = (RefereeBits())[RandomInt(Length(RefereeBits()))];
|
||||
let strategies = [QuantumStrategy(rst[0], _), QuantumStrategy(rst[1], _), QuantumStrategy(rst[2], _)];
|
||||
let abc = PlayQuantumGHZ(strategies);
|
||||
AssertBoolEqual(WinCondition_Reference(rst, abc), true,
|
||||
EqualityFactB(WinCondition_Reference(rst, abc), true,
|
||||
$"Quantum strategy lost: for rst={rst} the players returned abc={abc}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -10,90 +10,74 @@
|
|||
|
||||
namespace Quantum.Kata.GroversAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part I. Oracles for Grover's Search
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. The |11...1⟩ oracle
|
||||
operation Oracle_AllOnes_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
Controlled X(queryRegister, target);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_AllOnes_Reference (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
Controlled X(queryRegister, target);
|
||||
}
|
||||
|
||||
|
||||
// Task 1.2. The |1010...⟩ oracle
|
||||
operation Oracle_AlternatingBits_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// flip the bits in odd (0-based positions),
|
||||
// so that the condition for flipping the state of the target qubit is "query register is in 1...1 state"
|
||||
FlipOddPositionBits_Reference(queryRegister);
|
||||
Controlled X(queryRegister, target);
|
||||
Adjoint FlipOddPositionBits_Reference(queryRegister);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_AlternatingBits_Reference (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
|
||||
// flip the bits in odd (0-based positions),
|
||||
// so that the condition for flipping the state of the target qubit is "query register is in 1...1 state"
|
||||
FlipOddPositionBits_Reference(queryRegister);
|
||||
Controlled X(queryRegister, target);
|
||||
Adjoint FlipOddPositionBits_Reference(queryRegister);
|
||||
}
|
||||
|
||||
|
||||
operation FlipOddPositionBits_Reference (register : Qubit[]) : Unit {
|
||||
operation FlipOddPositionBits_Reference (register : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// iterate over elements in odd positions (indexes are 0-based)
|
||||
for (i in 1 .. 2 .. Length(register) - 1) {
|
||||
X(register[i]);
|
||||
}
|
||||
// iterate over elements in odd positions (indexes are 0-based)
|
||||
for (i in 1 .. 2 .. Length(register) - 1) {
|
||||
X(register[i]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.3. Arbitrary bit pattern oracle
|
||||
operation Oracle_ArbitraryPattern_Reference (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
(ControlledOnBitString(pattern, X))(queryRegister, target);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_ArbitraryPattern_Reference (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : Unit
|
||||
is Adj {
|
||||
(ControlledOnBitString(pattern, X))(queryRegister, target);
|
||||
}
|
||||
|
||||
|
||||
// Task 1.4*. Oracle converter
|
||||
operation OracleConverterImpl_Reference (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint), register : Qubit[]) : Unit {
|
||||
operation OracleConverterImpl_Reference (markingOracle : ((Qubit[], Qubit) => Unit is Adj), register : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
using (target = Qubit()) {
|
||||
// Put the target into the |-⟩ state
|
||||
X(target);
|
||||
H(target);
|
||||
using (target = Qubit()) {
|
||||
// Put the target into the |-⟩ state
|
||||
X(target);
|
||||
H(target);
|
||||
|
||||
// Apply the marking oracle; since the target is in the |-⟩ state,
|
||||
// flipping the target if the register satisfies the oracle condition will apply a -1 factor to the state
|
||||
markingOracle(register, target);
|
||||
// Apply the marking oracle; since the target is in the |-⟩ state,
|
||||
// flipping the target if the register satisfies the oracle condition will apply a -1 factor to the state
|
||||
markingOracle(register, target);
|
||||
|
||||
// Put the target back into |0⟩ so we can return it
|
||||
H(target);
|
||||
X(target);
|
||||
}
|
||||
// Put the target back into |0⟩ so we can return it
|
||||
H(target);
|
||||
X(target);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
function OracleConverter_Reference (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint)) : (Qubit[] => Unit : Adjoint) {
|
||||
function OracleConverter_Reference (markingOracle : ((Qubit[], Qubit) => Unit is Adj)) : (Qubit[] => Unit is Adj) {
|
||||
return OracleConverterImpl_Reference(markingOracle, _);
|
||||
}
|
||||
|
||||
|
@ -103,19 +87,16 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. The Hadamard transform
|
||||
operation HadamardTransform_Reference (register : Qubit[]) : Unit {
|
||||
operation HadamardTransform_Reference (register : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
ApplyToEachA(H, register);
|
||||
ApplyToEachA(H, register);
|
||||
|
||||
// ApplyToEach is a library routine that is equivalent to the following code:
|
||||
// let nQubits = Length(register);
|
||||
// for (idxQubit in 0..nQubits - 1) {
|
||||
// H(register[idxQubit]);
|
||||
// }
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// ApplyToEach is a library routine that is equivalent to the following code:
|
||||
// let nQubits = Length(register);
|
||||
// for (idxQubit in 0..nQubits - 1) {
|
||||
// H(register[idxQubit]);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
@ -149,16 +130,13 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
|
||||
|
||||
// Task 2.3. The Grover iteration
|
||||
operation GroverIteration_Reference (register : Qubit[], oracle : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
operation GroverIteration_Reference (register : Qubit[], oracle : (Qubit[] => Unit is Adj)) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
oracle(register);
|
||||
HadamardTransform_Reference(register);
|
||||
ConditionalPhaseFlip_Reference(register);
|
||||
HadamardTransform_Reference(register);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
oracle(register);
|
||||
HadamardTransform_Reference(register);
|
||||
ConditionalPhaseFlip_Reference(register);
|
||||
HadamardTransform_Reference(register);
|
||||
}
|
||||
|
||||
|
||||
|
@ -167,18 +145,15 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 3.1. Grover's search
|
||||
operation GroversSearch_Reference (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint), iterations : Int) : Unit {
|
||||
operation GroversSearch_Reference (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit is Adj), iterations : Int) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
let phaseOracle = OracleConverter_Reference(oracle);
|
||||
HadamardTransform_Reference(register);
|
||||
let phaseOracle = OracleConverter_Reference(oracle);
|
||||
HadamardTransform_Reference(register);
|
||||
|
||||
for (i in 1 .. iterations) {
|
||||
GroverIteration_Reference(register, phaseOracle);
|
||||
}
|
||||
for (i in 1 .. iterations) {
|
||||
GroverIteration_Reference(register, phaseOracle);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
namespace Quantum.Kata.GroversAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -18,7 +19,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// It covers the following topics:
|
||||
// - writing oracles for Grover's search,
|
||||
// - performing steps of the algorithm, and
|
||||
// - putting it all together: Grover's search algorithm.
|
||||
// - putting it all together: Grover's search algorithm.
|
||||
|
||||
// Each task is wrapped in one operation preceded by the description of the task.
|
||||
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
|
||||
|
@ -94,7 +95,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
body (...) {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(queryRegister), Length(pattern), "Arrays should have the same length");
|
||||
EqualityFactI(Length(queryRegister), Length(pattern), "Arrays should have the same length");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -113,7 +114,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// but it is often easier to write a marking oracle for a given condition. This transformation
|
||||
// allows to convert one type of oracle into the other. The transformation is described at
|
||||
// https://en.wikipedia.org/wiki/Grover%27s_algorithm, section "Description of Uω".
|
||||
function OracleConverter (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint)) : (Qubit[] => Unit : Adjoint) {
|
||||
function OracleConverter (markingOracle : ((Qubit[], Qubit) => Unit is Adj)) : (Qubit[] => Unit is Adj) {
|
||||
|
||||
// Hint: Remember that you can define auxiliary operations.
|
||||
|
||||
|
@ -135,13 +136,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
//
|
||||
// Note: If the register started in the |0...0⟩ state, this operation
|
||||
// will prepare an equal superposition of all 2^N basis states.
|
||||
operation HadamardTransform (register : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation HadamardTransform (register : Qubit[]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -152,19 +149,16 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// If the register is in state |0...0⟩, leave it unchanged.
|
||||
// If the register is in any other basis state, multiply its phase by -1.
|
||||
// Note: This operation implements operator 2|0...0⟩⟨0...0| - I.
|
||||
operation ConditionalPhaseFlip (register : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// Hint 1: Note that quantum states are defined up to a global phase.
|
||||
// Thus the state obtained as a result of this operation is the same
|
||||
// as the state obtained by flipping the sign of only the |0...0⟩ state.
|
||||
operation ConditionalPhaseFlip (register : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
// Hint 1: Note that quantum states are defined up to a global phase.
|
||||
// Thus the state obtained as a result of this operation is the same
|
||||
// as the state obtained by flipping the sign of only the |0...0⟩ state.
|
||||
|
||||
// Hint 2: You can use the same trick as in the oracle converter task.
|
||||
// Hint 2: You can use the same trick as in the oracle converter task.
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,19 +168,16 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// 2) a phase-flipping oracle that takes an N-qubit register and flips
|
||||
// the phase of the state if the register is in the desired state.
|
||||
// Goal: Perform one Grover iteration.
|
||||
operation GroverIteration (register : Qubit[], oracle : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
operation GroverIteration (register : Qubit[], oracle : (Qubit[] => Unit is Adj)) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// Hint: A Grover iteration consists of 4 steps:
|
||||
// 1) apply the oracle
|
||||
// 2) apply the Hadamard transform
|
||||
// 3) perform a conditional phase shift
|
||||
// 4) apply the Hadamard transform again
|
||||
// Hint: A Grover iteration consists of 4 steps:
|
||||
// 1) apply the oracle
|
||||
// 2) apply the Hadamard transform
|
||||
// 3) perform a conditional phase shift
|
||||
// 4) apply the Hadamard transform again
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,8 +195,8 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
//
|
||||
// Note: The number of iterations is passed as a parameter because it is defined by the nature of the problem
|
||||
// and is easier to configure/calculate outside the search algorithm itself (for example, in the driver).
|
||||
operation GroversSearch (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint), iterations : Int) : Unit {
|
||||
// ...
|
||||
operation GroversSearch (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit is Adj), iterations : Int) : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -214,16 +205,17 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// to find the marked elements of the search space.
|
||||
// This task is not covered by a test and allows you to experiment with running the algorithm.
|
||||
operation E2E_GroversSearch_Test () : Unit {
|
||||
// Hint 1: To check whether the algorithm found the correct answer (i.e., an answer marked as 1 by the oracle),
|
||||
// you can apply the oracle once more to the register after you've measured it and an ancilla qubit,
|
||||
// which will calculate the function of the answer found by the algorithm.
|
||||
|
||||
// Hint 2: Experiment with the number of iterations to see how it affects
|
||||
// the probability of the algorithm finding the correct answer.
|
||||
// Hint 1: To check whether the algorithm found the correct answer (i.e., an answer marked as 1 by the oracle),
|
||||
// you can apply the oracle once more to the register after you've measured it and an ancilla qubit,
|
||||
// which will calculate the function of the answer found by the algorithm.
|
||||
|
||||
// Hint 3: You can use the Message function to write the results to the console.
|
||||
// Hint 2: Experiment with the number of iterations to see how it affects
|
||||
// the probability of the algorithm finding the correct answer.
|
||||
|
||||
// ...
|
||||
// Hint 3: You can use the Message function to write the results to the console.
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,30 +9,27 @@
|
|||
|
||||
namespace Quantum.Kata.GroversAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// helper wrapper to represent oracle operation on input and output registers as an operation on an array of qubits
|
||||
operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit) => Unit : Adjoint), qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
op(Most(qs), Tail(qs));
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit) => Unit is Adj), qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
op(Most(qs), Tail(qs));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// helper wrapper to test for operation equality on various register sizes
|
||||
operation AssertRegisterOperationsEqual (testOp : (Qubit[] => Unit), refOp : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
operation AssertRegisterOperationsEqual (testOp : (Qubit[] => Unit), refOp : (Qubit[] => Unit is Adj)) : Unit {
|
||||
for (n in 2 .. 10) {
|
||||
AssertOperationsEqualReferenced(testOp, refOp, n);
|
||||
AssertOperationsEqualReferenced(n, testOp, refOp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +56,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
let pattern = BoolArrFromPositiveInt(RandomIntPow2(n), n);
|
||||
let testOp = QubitArrayWrapperOperation(Oracle_ArbitraryPattern(_, _, pattern), _);
|
||||
let refOp = QubitArrayWrapperOperation(Oracle_ArbitraryPattern_Reference(_, _, pattern), _);
|
||||
AssertOperationsEqualReferenced(testOp, refOp, n + 1);
|
||||
AssertOperationsEqualReferenced(n + 1, testOp, refOp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +68,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
|
||||
let phaseOracleRef = OracleConverter_Reference(markingOracle);
|
||||
let phaseOracleSol = OracleConverter(markingOracle);
|
||||
AssertOperationsEqualReferenced(phaseOracleSol, phaseOracleRef, n);
|
||||
AssertOperationsEqualReferenced(n, phaseOracleSol, phaseOracleRef);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +93,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
let flipOracle = OracleConverter_Reference(markingOracle);
|
||||
let testOp = GroverIteration(_, flipOracle);
|
||||
let refOp = GroverIteration_Reference(_, flipOracle);
|
||||
AssertOperationsEqualReferenced(testOp, refOp, n);
|
||||
AssertOperationsEqualReferenced(n, testOp, refOp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +105,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
let markingOracle = Oracle_ArbitraryPattern_Reference(_, _, pattern);
|
||||
let testOp = GroversSearch(_, markingOracle, 4);
|
||||
let refOp = GroversSearch_Reference(_, markingOracle, 4);
|
||||
AssertOperationsEqualReferenced(testOp, refOp, n);
|
||||
AssertOperationsEqualReferenced(n, testOp, refOp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
|
||||
namespace Quantum.Kata.JointMeasurements {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Characterization;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// Task 1. Single-qubit measurement
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
namespace Quantum.Kata.JointMeasurements {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
|
||||
namespace Quantum.Kata.JointMeasurements {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// "Framework" operation for testing multi-qubit tasks for distinguishing states of an array of qubits
|
||||
// with Int return
|
||||
operation DistinguishStates_MultiQubit (Nqubit : Int, Nstate : Int, statePrep : ((Qubit[], Int, Double) => Unit : Adjoint), testImpl : (Qubit[] => Int), preserveState : Bool) : Unit {
|
||||
operation DistinguishStates_MultiQubit (Nqubit : Int, Nstate : Int, statePrep : ((Qubit[], Int, Double) => Unit is Adj), testImpl : (Qubit[] => Int), preserveState : Bool) : Unit {
|
||||
let nTotal = 100;
|
||||
mutable nOk = 0;
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace Quantum.Kata.JointMeasurements {
|
|||
// get the solution's answer and verify that it's a match
|
||||
let ans = testImpl(qs);
|
||||
if (ans == state) {
|
||||
set nOk = nOk + 1;
|
||||
set nOk += 1;
|
||||
}
|
||||
|
||||
if (preserveState) {
|
||||
|
@ -50,29 +50,26 @@ namespace Quantum.Kata.JointMeasurements {
|
|||
}
|
||||
}
|
||||
|
||||
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
|
||||
EqualityFactI(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation StatePrep_ParityMeasurement (qs : Qubit[], state : Int, alpha : Double) : Unit {
|
||||
operation StatePrep_ParityMeasurement (qs : Qubit[], state : Int, alpha : Double) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// prep cos(alpha) * |0..0⟩ + sin(alpha) * |1..1⟩
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
for (i in 1 .. Length(qs) - 1) {
|
||||
CNOT(qs[0], qs[i]);
|
||||
}
|
||||
// prep cos(alpha) * |0..0⟩ + sin(alpha) * |1..1⟩
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
for (i in 1 .. Length(qs) - 1) {
|
||||
CNOT(qs[0], qs[i]);
|
||||
}
|
||||
|
||||
if (state == 1) {
|
||||
// flip the state of the last half of the qubits
|
||||
for (i in 0 .. Length(qs) / 2 - 1) {
|
||||
X(qs[i]);
|
||||
}
|
||||
if (state == 1) {
|
||||
// flip the state of the last half of the qubits
|
||||
for (i in 0 .. Length(qs) / 2 - 1) {
|
||||
X(qs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,46 +92,38 @@ namespace Quantum.Kata.JointMeasurements {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation StatePrep_WState_Arbitrary (qs : Qubit[]) : Unit {
|
||||
operation StatePrep_WState_Arbitrary (qs : Qubit[]) : Unit
|
||||
is Adj + Ctl {
|
||||
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
let N = Length(qs);
|
||||
|
||||
if (N == 1) {
|
||||
// base case of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
}
|
||||
else {
|
||||
// |W_N> = |0⟩|W_(N-1)> + |1⟩|0...0⟩
|
||||
// do a rotation on the first qubit to split it into |0⟩ and |1⟩ with proper weights
|
||||
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
|
||||
let theta = ArcSin(1.0 / Sqrt(ToDouble(N)));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
|
||||
// do a zero-controlled W-state generation for qubits 1..N-1
|
||||
X(qs[0]);
|
||||
Controlled StatePrep_WState_Arbitrary(qs[0 .. 0], qs[1 .. N - 1]);
|
||||
X(qs[0]);
|
||||
}
|
||||
if (N == 1) {
|
||||
// base case of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
}
|
||||
else {
|
||||
// |W_N> = |0⟩|W_(N-1)> + |1⟩|0...0⟩
|
||||
// do a rotation on the first qubit to split it into |0⟩ and |1⟩ with proper weights
|
||||
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
|
||||
let theta = ArcSin(1.0 / Sqrt(IntAsDouble(N)));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
|
||||
// do a zero-controlled W-state generation for qubits 1..N-1
|
||||
X(qs[0]);
|
||||
Controlled StatePrep_WState_Arbitrary(qs[0 .. 0], qs[1 .. N - 1]);
|
||||
X(qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
controlled distribute;
|
||||
controlled adjoint distribute;
|
||||
}
|
||||
|
||||
|
||||
operation StatePrep_GHZOrWState (qs : Qubit[], state : Int, alpha : Double) : Unit {
|
||||
operation StatePrep_GHZOrWState (qs : Qubit[], state : Int, alpha : Double) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
if (state == 0) {
|
||||
StatePrep_ParityMeasurement(qs, 0, alpha);
|
||||
} else {
|
||||
StatePrep_WState_Arbitrary(qs);
|
||||
}
|
||||
if (state == 0) {
|
||||
StatePrep_ParityMeasurement(qs, 0, alpha);
|
||||
} else {
|
||||
StatePrep_WState_Arbitrary(qs);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -146,22 +135,19 @@ namespace Quantum.Kata.JointMeasurements {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation StatePrep_DifferentBasis (qs : Qubit[], state : Int, alpha : Double) : Unit {
|
||||
operation StatePrep_DifferentBasis (qs : Qubit[], state : Int, alpha : Double) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// prep cos(alpha) * |00⟩ + sin(alpha) * |11⟩
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
// prep cos(alpha) * |00⟩ + sin(alpha) * |11⟩
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
|
||||
if (state == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
|
||||
// convert to X basis
|
||||
ApplyToEachA(H, qs);
|
||||
if (state == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
|
||||
// convert to X basis
|
||||
ApplyToEachA(H, qs);
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,13 +158,9 @@ namespace Quantum.Kata.JointMeasurements {
|
|||
|
||||
// ------------------------------------------------------
|
||||
// prepare state |A⟩ = cos(α) * |0⟩ + sin(α) * |1⟩
|
||||
operation StatePrep_A (alpha : Double, q : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
Ry(2.0 * alpha, q);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation StatePrep_A (alpha : Double, q : Qubit) : Unit
|
||||
is Adj {
|
||||
Ry(2.0 * alpha, q);
|
||||
}
|
||||
|
||||
|
||||
|
@ -189,7 +171,7 @@ namespace Quantum.Kata.JointMeasurements {
|
|||
using (qs = Qubit[2]) {
|
||||
|
||||
for (i in 0 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
|
||||
// prepare A state
|
||||
StatePrep_A(alpha, qs[0]);
|
||||
|
@ -221,8 +203,8 @@ namespace Quantum.Kata.JointMeasurements {
|
|||
|
||||
operation T07_ControlledX_General_Test () : Unit {
|
||||
// In this task the gate is supposed to work on all inputs, so we can compare the unitary to CNOT.
|
||||
AssertOperationsEqualReferenced(CNOTWrapper, ControlledX_General_Reference, 2);
|
||||
AssertOperationsEqualReferenced(ControlledX_General, ControlledX_General_Reference, 2);
|
||||
AssertOperationsEqualReferenced(2, CNOTWrapper, ControlledX_General_Reference);
|
||||
AssertOperationsEqualReferenced(2, ControlledX_General, ControlledX_General_Reference);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%package Microsoft.Quantum.Katas::0.5.1904.1302"
|
||||
"%package Microsoft.Quantum.Katas::0.6.1905.301"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -42,13 +42,13 @@
|
|||
"> The package versions in the output of the cell above should always match. If you are running the Notebooks locally and the versions do not match, please install the IQ# version that matches the version of the `Microsoft.Quantum.Katas` package.\n",
|
||||
"> <details>\n",
|
||||
"> <summary><u>How to install the right IQ# version</u></summary>\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.5.1904.1302, the installation steps are as follows:\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.6.1905.301, the installation steps are as follows:\n",
|
||||
">\n",
|
||||
"> 1. Stop the kernel.\n",
|
||||
"> 2. Uninstall the existing version of IQ#:\n",
|
||||
"> dotnet tool uninstall microsoft.quantum.iqsharp -g\n",
|
||||
"> 3. Install the matching version:\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.5.1904.1302\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.6.1905.301\n",
|
||||
"> 4. Reinstall the kernel:\n",
|
||||
"> dotnet iqsharp install\n",
|
||||
"> 5. Restart the Notebook.\n",
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
|
||||
namespace Quantum.Kata.Measurements {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Measurement;
|
||||
open Microsoft.Quantum.Arithmetic;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
@ -139,7 +141,7 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
for (q in qs) {
|
||||
if (M(q) == One) {
|
||||
set countOnes = countOnes + 1;
|
||||
set countOnes += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +167,7 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
for (q in qs) {
|
||||
if (M(q) == One) {
|
||||
set countOnes = countOnes + 1;
|
||||
set countOnes += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +431,6 @@ namespace Quantum.Kata.Measurements {
|
|||
// |+⟩ | std | 0 | 1/2 | 1/2
|
||||
// |0⟩ | had | 1/2 | 0 | 1/2
|
||||
// |+⟩ | had | 0 | 0 | 1
|
||||
mutable output = 0;
|
||||
let basis = RandomInt(2);
|
||||
|
||||
// randomize over std and had
|
||||
|
@ -437,28 +438,16 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
// use standard basis
|
||||
let result = M(q);
|
||||
if (result == One) {
|
||||
// this can only arise if the state was |+⟩
|
||||
set output = 1;
|
||||
}
|
||||
else {
|
||||
set output = -1;
|
||||
}
|
||||
// result is One only if the state was |+⟩
|
||||
return result == One ? 1 | -1;
|
||||
}
|
||||
else {
|
||||
// use Hadamard basis
|
||||
H(q);
|
||||
let result = M(q);
|
||||
if (result == One) {
|
||||
// this can only arise if the state was |0⟩
|
||||
set output = 0;
|
||||
}
|
||||
else {
|
||||
set output = -1;
|
||||
}
|
||||
// result is One only if the state was |0⟩
|
||||
return result == One ? 0 | -1;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
|
@ -468,7 +457,7 @@ namespace Quantum.Kata.Measurements {
|
|||
// |A⟩ = 1/sqrt(2) (|0⟩ + |1⟩),
|
||||
// |B⟩ = 1/sqrt(2) (|0⟩ + ω |1⟩),
|
||||
// |C⟩ = 1/sqrt(2) (|0⟩ + ω² |1⟩).
|
||||
// where ω = exp(2π/3) denotes a primitive, complex 3rd root of unity.
|
||||
// where ω = exp(2π/3) denotes a primitive, complex 3rd root of unity.
|
||||
// Output: 1 or 2 if qubit was in the |A⟩ state,
|
||||
// 0 or 2 if qubit was in the |B⟩ state,
|
||||
// 0 or 1 if qubit was in the |C⟩ state.
|
||||
|
@ -489,7 +478,6 @@ namespace Quantum.Kata.Measurements {
|
|||
// a 4x4 unitary. Using the "Rader trick" we can now block decompose the 3x3 DFT and obtain two
|
||||
// 2x2 blocks which we can then implement using controlled single qubit gates. We present
|
||||
// the final resulting circuit without additional commentary.
|
||||
mutable output = 0;
|
||||
let alpha = ArcCos(Sqrt(2.0 / 3.0));
|
||||
|
||||
using (a = Qubit()) {
|
||||
|
@ -510,20 +498,18 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
// dispatch on the cases
|
||||
if (res0 == Zero and res1 == Zero) {
|
||||
set output = 0;
|
||||
return 0;
|
||||
}
|
||||
elif (res0 == One and res1 == Zero) {
|
||||
set output = 1;
|
||||
return 1;
|
||||
}
|
||||
elif (res0 == Zero and res1 == One) {
|
||||
set output = 2;
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
// this should never occur
|
||||
set output = 3;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
namespace Quantum.Kata.Measurements {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
@ -270,7 +270,7 @@ namespace Quantum.Kata.Measurements {
|
|||
// |A⟩ = 1/sqrt(2) (|0⟩ + |1⟩),
|
||||
// |B⟩ = 1/sqrt(2) (|0⟩ + ω |1⟩),
|
||||
// |C⟩ = 1/sqrt(2) (|0⟩ + ω² |1⟩),
|
||||
// where ω = exp(2iπ/3) denotes a primitive, complex 3rd root of unity.
|
||||
// where ω = exp(2iπ/3) denotes a primitive, complex 3rd root of unity.
|
||||
// Output: 1 or 2 if the qubit was in the |A⟩ state,
|
||||
// 0 or 2 if the qubit was in the |B⟩ state,
|
||||
// 0 or 1 if the qubit was in the |C⟩ state.
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
|
||||
namespace Quantum.Kata.Measurements {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
open Quantum.Kata.Utils;
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace Quantum.Kata.Measurements {
|
|||
// get the solution's answer and verify that it's a match
|
||||
let ans = testImpl(qs[0]);
|
||||
if (ans == (state == 1)) {
|
||||
set nOk = nOk + 1;
|
||||
set nOk += 1;
|
||||
}
|
||||
|
||||
// we're not checking the state of the qubit after the operation
|
||||
|
@ -46,15 +46,13 @@ namespace Quantum.Kata.Measurements {
|
|||
}
|
||||
}
|
||||
|
||||
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
|
||||
EqualityFactI(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation StatePrep_IsQubitOne (q : Qubit, state : Int) : Unit {
|
||||
if (state == 0) {
|
||||
// convert |0⟩ to |0⟩
|
||||
} else {
|
||||
if (state != 0) {
|
||||
// convert |0⟩ to |1⟩
|
||||
X(q);
|
||||
}
|
||||
|
@ -70,7 +68,7 @@ namespace Quantum.Kata.Measurements {
|
|||
operation T102_InitializeQubit_Test () : Unit {
|
||||
using (qs = Qubit[1]) {
|
||||
for (i in 0 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
|
||||
// Test Task 1
|
||||
|
@ -126,7 +124,7 @@ namespace Quantum.Kata.Measurements {
|
|||
DistinguishTwoStates_OneQubit(StatePrep_IsQubitPlus, IsQubitA(PI() / 4.0, _));
|
||||
|
||||
for (i in 0 .. 10) {
|
||||
let alpha = (PI() * ToDouble(i)) / 10.0;
|
||||
let alpha = (PI() * IntAsDouble(i)) / 10.0;
|
||||
DistinguishTwoStates_OneQubit(StatePrep_IsQubitA(alpha, _, _), IsQubitA(alpha, _));
|
||||
}
|
||||
}
|
||||
|
@ -158,12 +156,12 @@ namespace Quantum.Kata.Measurements {
|
|||
// get the solution's answer and verify that it's a match
|
||||
let ans = testImpl(qs);
|
||||
if (ans == state) {
|
||||
set nOk = nOk + 1;
|
||||
set nOk += 1;
|
||||
}
|
||||
// if we have a max number of measurements per solution run specified, check that it is not exceeded
|
||||
if (measurementsPerRun > 0) {
|
||||
let nm = GetOracleCallsCount(M) + GetOracleCallsCount(Measure);
|
||||
AssertBoolEqual(nm <= 1, true, $"You are allowed to do at most one measurement, and you did {nm}");
|
||||
EqualityFactB(nm <= 1, true, $"You are allowed to do at most one measurement, and you did {nm}");
|
||||
}
|
||||
|
||||
// we're not checking the state of the qubit after the operation
|
||||
|
@ -171,7 +169,7 @@ namespace Quantum.Kata.Measurements {
|
|||
}
|
||||
}
|
||||
|
||||
AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
|
||||
EqualityFactI(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state.");
|
||||
}
|
||||
|
||||
|
||||
|
@ -221,11 +219,8 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
|
||||
operation StatePrep_TwoBitstringsMeasurement (qs : Qubit[], bits1 : Bool[], bits2 : Bool[], state : Int) : Unit {
|
||||
if (state == 0) {
|
||||
StatePrep_Bitstring(qs, bits1);
|
||||
} else {
|
||||
StatePrep_Bitstring(qs, bits2);
|
||||
}
|
||||
let bits = state == 0 ? bits1 | bits2;
|
||||
StatePrep_Bitstring(qs, bits);
|
||||
}
|
||||
|
||||
|
||||
|
@ -243,31 +238,25 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation WState_Arbitrary_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
operation WState_Arbitrary_Reference (qs : Qubit[]) : Unit
|
||||
is Adj + Ctl {
|
||||
let N = Length(qs);
|
||||
|
||||
if (N == 1) {
|
||||
// base case of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
} else {
|
||||
// |W_N> = |0⟩|W_(N-1)> + |1⟩|0...0⟩
|
||||
// do a rotation on the first qubit to split it into |0⟩ and |1⟩ with proper weights
|
||||
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
|
||||
let theta = ArcSin(1.0 / Sqrt(ToDouble(N)));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
if (N == 1) {
|
||||
// base case of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
} else {
|
||||
// |W_N> = |0⟩|W_(N-1)> + |1⟩|0...0⟩
|
||||
// do a rotation on the first qubit to split it into |0⟩ and |1⟩ with proper weights
|
||||
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
|
||||
let theta = ArcSin(1.0 / Sqrt(IntAsDouble(N)));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
|
||||
// do a zero-controlled W-state generation for qubits 1..N-1
|
||||
X(qs[0]);
|
||||
Controlled WState_Arbitrary_Reference(qs[0 .. 0], qs[1 .. N - 1]);
|
||||
X(qs[0]);
|
||||
}
|
||||
// do a zero-controlled W-state generation for qubits 1..N-1
|
||||
X(qs[0]);
|
||||
Controlled WState_Arbitrary_Reference(qs[0 .. 0], qs[1 .. N - 1]);
|
||||
X(qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
controlled distribute;
|
||||
controlled adjoint distribute;
|
||||
}
|
||||
|
||||
|
||||
|
@ -289,16 +278,13 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation GHZ_State_Reference (qs : Qubit[]) : Unit {
|
||||
operation GHZ_State_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
H(qs[0]);
|
||||
for (i in 1 .. Length(qs) - 1) {
|
||||
CNOT(qs[0], qs[i]);
|
||||
}
|
||||
H(qs[0]);
|
||||
for (i in 1 .. Length(qs) - 1) {
|
||||
CNOT(qs[0], qs[i]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -393,23 +379,20 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
// ------------------------------------------------------
|
||||
|
||||
operation StatePrep_ThreeQubitMeasurement (qs : Qubit[], state : Int) : Unit {
|
||||
operation StatePrep_ThreeQubitMeasurement (qs : Qubit[], state : Int) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
WState_Arbitrary_Reference(qs);
|
||||
WState_Arbitrary_Reference(qs);
|
||||
|
||||
if (state == 0) {
|
||||
// prep 1/sqrt(3) ( |100⟩ + ω |010⟩ + ω² |001⟩ )
|
||||
R1(2.0 * PI() / 3.0, qs[1]);
|
||||
R1(4.0 * PI() / 3.0, qs[2]);
|
||||
} else {
|
||||
// prep 1/sqrt(3) ( |100⟩ + ω² |010⟩ + ω |001⟩ )
|
||||
R1(4.0 * PI() / 3.0, qs[1]);
|
||||
R1(2.0 * PI() / 3.0, qs[2]);
|
||||
}
|
||||
if (state == 0) {
|
||||
// prep 1/sqrt(3) ( |100⟩ + ω |010⟩ + ω² |001⟩ )
|
||||
R1(2.0 * PI() / 3.0, qs[1]);
|
||||
R1(4.0 * PI() / 3.0, qs[2]);
|
||||
} else {
|
||||
// prep 1/sqrt(3) ( |100⟩ + ω² |010⟩ + ω |001⟩ )
|
||||
R1(4.0 * PI() / 3.0, qs[1]);
|
||||
R1(2.0 * PI() / 3.0, qs[2]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
operation T113_ThreeQubitMeasurement_Test () : Unit {
|
||||
|
@ -423,9 +406,7 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
operation StatePrep_IsQubitZeroOrPlus (q : Qubit, state : Int) : Unit {
|
||||
|
||||
if (state == 0) {
|
||||
// convert |0⟩ to |0⟩
|
||||
} else {
|
||||
if (state != 0) {
|
||||
// convert |0⟩ to |+⟩
|
||||
H(q);
|
||||
}
|
||||
|
@ -449,7 +430,7 @@ namespace Quantum.Kata.Measurements {
|
|||
// get the solution's answer and verify that it's a match
|
||||
let ans = testImpl(qs[0]);
|
||||
if (ans == (state == 0)) {
|
||||
set nOk = nOk + 1;
|
||||
set nOk += 1;
|
||||
}
|
||||
|
||||
// we're not checking the state of the qubit after the operation
|
||||
|
@ -457,7 +438,7 @@ namespace Quantum.Kata.Measurements {
|
|||
}
|
||||
}
|
||||
|
||||
if (ToDouble(nOk) < threshold * ToDouble(nTotal)) {
|
||||
if (IntAsDouble(nOk) < threshold * IntAsDouble(nTotal)) {
|
||||
fail $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state which does not meet the required threshold of at least {threshold * 100.0}%.";
|
||||
}
|
||||
}
|
||||
|
@ -504,15 +485,15 @@ namespace Quantum.Kata.Measurements {
|
|||
|
||||
// keep track of the number of inconclusive answers given
|
||||
if (ans == -1) {
|
||||
set nInconc = nInconc + 1;
|
||||
set nInconc += 1;
|
||||
}
|
||||
|
||||
if (ans == 0 and state == 0) {
|
||||
set nConclOne = nConclOne + 1;
|
||||
set nConclOne += 1;
|
||||
}
|
||||
|
||||
if (ans == 1 and state == 1) {
|
||||
set nConclPlus = nConclPlus + 1;
|
||||
set nConclPlus += 1;
|
||||
}
|
||||
|
||||
// check if upon conclusive result the answer is actually correct
|
||||
|
@ -525,15 +506,15 @@ namespace Quantum.Kata.Measurements {
|
|||
}
|
||||
}
|
||||
|
||||
if (ToDouble(nInconc) > thresholdInconcl * ToDouble(nTotal)) {
|
||||
if (IntAsDouble(nInconc) > thresholdInconcl * IntAsDouble(nTotal)) {
|
||||
fail $"{nInconc} test runs out of {nTotal} returned inconclusive which does not meet the required threshold of at most {thresholdInconcl * 100.0}%.";
|
||||
}
|
||||
|
||||
if (ToDouble(nConclOne) < thresholdConcl * ToDouble(nTotal)) {
|
||||
if (IntAsDouble(nConclOne) < thresholdConcl * IntAsDouble(nTotal)) {
|
||||
fail $"Only {nConclOne} test runs out of {nTotal} returned conclusive |0⟩ which does not meet the required threshold of at least {thresholdConcl * 100.0}%.";
|
||||
}
|
||||
|
||||
if (ToDouble(nConclPlus) < thresholdConcl * ToDouble(nTotal)) {
|
||||
if (IntAsDouble(nConclPlus) < thresholdConcl * IntAsDouble(nTotal)) {
|
||||
fail $"Only {nConclPlus} test runs out of {nTotal} returned conclusive |+> which does not meet the required threshold of at least {thresholdConcl * 100.0}%.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace Quantum.Kata.PhaseEstimation
|
|||
return base.Apply();
|
||||
}
|
||||
|
||||
public override QArray<Qubit> Apply(long count)
|
||||
public override IQArray<Qubit> Apply(long count)
|
||||
{
|
||||
_sim._qubitsAllocated += count;
|
||||
if (_sim._qubitsAllocated > _sim._maxQubitsAllocated)
|
||||
|
@ -140,7 +140,7 @@ namespace Quantum.Kata.PhaseEstimation
|
|||
base.Apply(q);
|
||||
}
|
||||
|
||||
public override void Apply(QArray<Qubit> qubits)
|
||||
public override void Apply(IQArray<Qubit> qubits)
|
||||
{
|
||||
_sim._qubitsAllocated -= qubits.Length;
|
||||
base.Apply(qubits);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -10,11 +10,15 @@
|
|||
|
||||
namespace Quantum.Kata.PhaseEstimation {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Measurement;
|
||||
open Microsoft.Quantum.Characterization;
|
||||
open Microsoft.Quantum.Arithmetic;
|
||||
open Microsoft.Quantum.Oracles;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
@ -22,39 +26,32 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. Inputs to QPE: eigenstates of Z/S/T gates.
|
||||
operation Eigenstates_ZST_Reference (q : Qubit, state : Int) : Unit {
|
||||
operation Eigenstates_ZST_Reference (q : Qubit, state : Int) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
if (state == 1) {
|
||||
X(q);
|
||||
}
|
||||
if (state == 1) {
|
||||
X(q);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation UnitaryPowerImpl_Reference (U : (Qubit => Unit : Adjoint, Controlled), power : Int, q : Qubit) : Unit {
|
||||
body (...) {
|
||||
for (i in 1..power) {
|
||||
U(q);
|
||||
}
|
||||
operation UnitaryPowerImpl_Reference (U : (Qubit => Unit is Adj + Ctl), power : Int, q : Qubit) : Unit
|
||||
is Adj + Ctl {
|
||||
for (i in 1..power) {
|
||||
U(q);
|
||||
}
|
||||
adjoint auto;
|
||||
controlled auto;
|
||||
controlled adjoint auto;
|
||||
}
|
||||
|
||||
// Task 1.2. Inputs to QPE: powers of Z/S/T gates.
|
||||
function UnitaryPower_Reference (U : (Qubit => Unit : Adjoint, Controlled), power : Int) : (Qubit => Unit : Adjoint, Controlled) {
|
||||
function UnitaryPower_Reference (U : (Qubit => Unit is Adj + Ctl), power : Int) : (Qubit => Unit is Adj + Ctl) {
|
||||
return UnitaryPowerImpl_Reference(U, power, _);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Task 1.3. Validate inputs to QPE
|
||||
operation AssertIsEigenstate_Reference (U : (Qubit => Unit), P : (Qubit => Unit : Adjoint)) : Unit {
|
||||
operation AssertIsEigenstate_Reference (U : (Qubit => Unit), P : (Qubit => Unit is Adj)) : Unit {
|
||||
using (q = Qubit()) {
|
||||
// Prepare the state |ψ⟩
|
||||
P(q);
|
||||
|
@ -69,22 +66,17 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation Oracle_Reference (U : (Qubit => Unit : Adjoint, Controlled), power : Int, target : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
for (i in 1 .. power) {
|
||||
U(target[0]);
|
||||
}
|
||||
operation Oracle_Reference (U : (Qubit => Unit is Adj + Ctl), power : Int, target : Qubit[]) : Unit
|
||||
is Adj + Ctl{
|
||||
for (i in 1 .. power) {
|
||||
U(target[0]);
|
||||
}
|
||||
adjoint auto;
|
||||
controlled auto;
|
||||
controlled adjoint auto;
|
||||
}
|
||||
|
||||
// Task 1.4. QPE for single-qubit unitaries
|
||||
operation QPE_Reference (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), n : Int) : Double {
|
||||
operation QPE_Reference (U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj), n : Int) : Double {
|
||||
// Construct a phase estimation oracle from the unitary
|
||||
let oracle = DiscreteOracle(Oracle_Reference(U, _, _));
|
||||
mutable phase = -1.0;
|
||||
// Allocate qubits to hold the eigenstate of U and the phase in a big endian register
|
||||
using ((eigenstate, phaseRegister) = (Qubit[1], Qubit[n])) {
|
||||
let phaseRegisterBE = BigEndian(phaseRegister);
|
||||
|
@ -93,13 +85,12 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// Call library
|
||||
QuantumPhaseEstimation(oracle, eigenstate, phaseRegisterBE);
|
||||
// Read out the phase
|
||||
set phase = ToDouble(MeasureIntegerBE(phaseRegisterBE)) / ToDouble(1 <<< n);
|
||||
let phase = IntAsDouble(MeasureIntegerBE(phaseRegisterBE)) / IntAsDouble(1 <<< n);
|
||||
|
||||
ResetAll(eigenstate);
|
||||
ResetAll(phaseRegister);
|
||||
return phase;
|
||||
}
|
||||
|
||||
return phase;
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,80 +99,70 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. Single-bit phase estimation
|
||||
operation SingleBitPE_Reference (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Int {
|
||||
mutable eigenvalue = 0;
|
||||
operation SingleBitPE_Reference (U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj)) : Int {
|
||||
using ((control, eigenstate) = (Qubit(), Qubit())) {
|
||||
// prepare the eigenstate |ψ⟩
|
||||
P(eigenstate);
|
||||
|
||||
H(control);
|
||||
(Controlled U)([control], eigenstate);
|
||||
Controlled U([control], eigenstate);
|
||||
H(control);
|
||||
|
||||
set eigenvalue = M(control) == Zero ? 1 | -1;
|
||||
|
||||
let eigenvalue = M(control) == Zero ? 1 | -1;
|
||||
ResetAll([control, eigenstate]);
|
||||
return eigenvalue;
|
||||
}
|
||||
return eigenvalue;
|
||||
}
|
||||
|
||||
|
||||
// Task 2.2. Two bit phase estimation
|
||||
operation TwoBitPE_Reference (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Double {
|
||||
operation TwoBitPE_Reference (U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj)) : Double {
|
||||
|
||||
// Start by using the same circuit as in task 2.1.
|
||||
// For eigenvalues +1 and -1, it produces measurement results Zero and One, respectively, 100% of the time;
|
||||
// for eigenvalues +i and -i, it produces both results with 50% probability, so a different circuit is required.
|
||||
mutable (nZero, nOne) = (0, 0);
|
||||
using ((control, eigenstate) = (Qubit(), Qubit())) {
|
||||
// prepare the eigenstate |ψ⟩
|
||||
P(eigenstate);
|
||||
|
||||
mutable (measuredZero, measuredOne) = (false, false);
|
||||
mutable iter = 0;
|
||||
repeat {
|
||||
set iter = iter + 1;
|
||||
set iter += 1;
|
||||
|
||||
H(control);
|
||||
(Controlled U)([control], eigenstate);
|
||||
Controlled U([control], eigenstate);
|
||||
H(control);
|
||||
|
||||
if (MResetZ(control) == Zero) {
|
||||
set nZero = nZero + 1;
|
||||
} else {
|
||||
set nOne = nOne + 1;
|
||||
}
|
||||
|
||||
// repeat the loop until we get both Zero and One measurement outcomes
|
||||
// or until we're reasonably certain that we won't get a different outcome
|
||||
} until (iter == 10 or nZero > 0 and nOne > 0)
|
||||
let meas = MResetZ(control);
|
||||
set (measuredZero, measuredOne) = (meas == Zero, meas == One);
|
||||
}
|
||||
// repeat the loop until we get both Zero and One measurement outcomes
|
||||
// or until we're reasonably certain that we won't get a different outcome
|
||||
until (iter == 10 or measuredZero and measuredOne)
|
||||
fixup {}
|
||||
|
||||
Reset(eigenstate);
|
||||
}
|
||||
|
||||
if (nOne == 0) {
|
||||
// all measurements yielded Zero => eigenvalue +1
|
||||
return 0.0;
|
||||
}
|
||||
if (nZero == 0) {
|
||||
// all measurements yielded One => eigenvalue -1
|
||||
return 0.5;
|
||||
if (not measuredZero or not measuredOne) {
|
||||
return measuredOne ? 0.5 | 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// To distinguish between eigenvalues i and -i, we need a circuit with an extra S gate on control qubit
|
||||
mutable eigenvalue = -1.0;
|
||||
using ((control, eigenstate) = (Qubit(), Qubit())) {
|
||||
// prepare the eigenstate |ψ⟩
|
||||
P(eigenstate);
|
||||
|
||||
H(control);
|
||||
(Controlled U)([control], eigenstate);
|
||||
Controlled U([control], eigenstate);
|
||||
S(control);
|
||||
H(control);
|
||||
|
||||
set eigenvalue = MResetZ(control) == Zero ? 0.75 | 0.25;
|
||||
|
||||
let eigenvalue = MResetZ(control) == Zero ? 0.75 | 0.25;
|
||||
Reset(eigenstate);
|
||||
return eigenvalue;
|
||||
}
|
||||
return eigenvalue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
namespace Quantum.Kata.PhaseEstimation {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Diagnostics;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Welcome!
|
||||
|
@ -41,13 +41,9 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// Goal:
|
||||
// Prepare one of the eigenstates of Z gate (which are the same as eigenstates of S or T gates):
|
||||
// eigenstate |0⟩ if state = 0, or eigenstate |1⟩ if state = 1.
|
||||
operation Eigenstates_ZST (q : Qubit, state : Int) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Eigenstates_ZST (q : Qubit, state : Int) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,7 +53,7 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// 2) a positive integer power.
|
||||
// Output:
|
||||
// A single-qubit unitary equal to U raised to the given power.
|
||||
function UnitaryPower (U : (Qubit => Unit : Adjoint, Controlled), power : Int) : (Qubit => Unit : Adjoint, Controlled) {
|
||||
function UnitaryPower (U : (Qubit => Unit is Adj + Ctl), power : Int) : (Qubit => Unit is Adj + Ctl) {
|
||||
// Hint: Remember that you can define auxiliary operations.
|
||||
|
||||
// ...
|
||||
|
@ -76,7 +72,7 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// Goal:
|
||||
// Assert that the given state is an eigenstate of the given unitary,
|
||||
// i.e., do nothing if it is, and throw an exception if it is not.
|
||||
operation AssertIsEigenstate (U : (Qubit => Unit), P : (Qubit => Unit : Adjoint)) : Unit {
|
||||
operation AssertIsEigenstate (U : (Qubit => Unit), P : (Qubit => Unit is Adj)) : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
@ -90,7 +86,7 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// Output:
|
||||
// The phase of the eigenvalue that corresponds to the eigenstate |ψ⟩, with n bits of precision.
|
||||
// The phase should be between 0 and 1.
|
||||
operation QPE (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), n : Int) : Double {
|
||||
operation QPE (U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj), n : Int) : Double {
|
||||
// ...
|
||||
return -1.0;
|
||||
}
|
||||
|
@ -138,7 +134,7 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// The eigenvalue which corresponds to the eigenstate |ψ⟩ (+1 or -1).
|
||||
//
|
||||
// You are allowed to allocate exactly two qubits and call Controlled U exactly once.
|
||||
operation SingleBitPE (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Int {
|
||||
operation SingleBitPE (U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj)) : Int {
|
||||
// Note: It is possible to use the QPE implementation from task 1.4 to solve this task,
|
||||
// but we suggest you implement the circuit by hand for the sake of learning.
|
||||
|
||||
|
@ -158,7 +154,7 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// The returned value has to be accurate within the absolute error of 0.001.
|
||||
//
|
||||
// You are allowed to allocate exactly two qubits and call Controlled U multiple times.
|
||||
operation TwoBitPE (U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint)) : Double {
|
||||
operation TwoBitPE (U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj)) : Double {
|
||||
// Hint: Start by applying the same circuit as in task 2.1.
|
||||
// What are the possible outcomes for each eigenvalue?
|
||||
// What eigenvalues you can and can not distinguish using this circuit?
|
||||
|
|
|
@ -9,18 +9,18 @@
|
|||
|
||||
namespace Quantum.Kata.PhaseEstimation {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part I. Quantum phase estimation (QPE)
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
operation AssertEqualOnZeroState1 (testImpl : (Qubit => Unit), refImpl : (Qubit => Unit : Adjoint)) : Unit {
|
||||
operation AssertEqualOnZeroState1 (testImpl : (Qubit => Unit), refImpl : (Qubit => Unit is Adj)) : Unit {
|
||||
using (q = Qubit()) {
|
||||
// apply operation that needs to be tested
|
||||
testImpl(q);
|
||||
|
@ -42,23 +42,17 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
|
||||
// ------------------------------------------------------
|
||||
// helper wrapper to represent operation on one qubit as an operation on an array of qubits
|
||||
operation ArrayWrapperOperation1 (op : (Qubit => Unit : Adjoint, Controlled), qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
op(qs[0]);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
controlled auto;
|
||||
controlled adjoint auto;
|
||||
operation ArrayWrapperOperation1 (op : (Qubit => Unit is Adj + Ctl), qs : Qubit[]) : Unit
|
||||
is Adj + Ctl {
|
||||
op(qs[0]);
|
||||
}
|
||||
|
||||
|
||||
operation T12_UnitaryPower_Test () : Unit {
|
||||
for (U in [Z, S, T]) {
|
||||
for (power in 1..5) {
|
||||
AssertOperationsEqualReferenced(ArrayWrapperOperation1(UnitaryPower(U, power), _),
|
||||
ArrayWrapperOperation1(UnitaryPower_Reference(U, power), _), 1);
|
||||
AssertOperationsEqualReferenced(1, ArrayWrapperOperation1(UnitaryPower(U, power), _),
|
||||
ArrayWrapperOperation1(UnitaryPower_Reference(U, power), _));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,14 +72,14 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
|
||||
// ------------------------------------------------------
|
||||
operation T14_QPE_Test () : Unit {
|
||||
AssertAlmostEqualTol(QPE(Z, I, 1), 0.0, 0.25);
|
||||
AssertAlmostEqualTol(QPE(Z, X, 1), 0.5, 0.25);
|
||||
EqualityWithinToleranceFact(QPE(Z, I, 1), 0.0, 0.25);
|
||||
EqualityWithinToleranceFact(QPE(Z, X, 1), 0.5, 0.25);
|
||||
|
||||
AssertAlmostEqualTol(QPE(S, I, 2), 0.0, 0.125);
|
||||
AssertAlmostEqualTol(QPE(S, X, 2), 0.25, 0.125);
|
||||
EqualityWithinToleranceFact(QPE(S, I, 2), 0.0, 0.125);
|
||||
EqualityWithinToleranceFact(QPE(S, X, 2), 0.25, 0.125);
|
||||
|
||||
AssertAlmostEqualTol(QPE(T, I, 3), 0.0, 0.0625);
|
||||
AssertAlmostEqualTol(QPE(T, X, 3), 0.125, 0.0625);
|
||||
EqualityWithinToleranceFact(QPE(T, I, 3), 0.0, 0.0625);
|
||||
EqualityWithinToleranceFact(QPE(T, X, 3), 0.125, 0.0625);
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,18 +87,18 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
// Part II. Iterative phase estimation
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
operation Test1BitPEOnOnePair(U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), expected : Int) : Unit {
|
||||
operation Test1BitPEOnOnePair(U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj), expected : Int) : Unit {
|
||||
ResetQubitCount();
|
||||
ResetOracleCallsCount();
|
||||
|
||||
let actual = SingleBitPE(U, P);
|
||||
AssertIntEqual(actual, expected, $"Unexpected return for ({U}, {P}): expected {expected}, got {actual}");
|
||||
EqualityFactI(actual, expected, $"Unexpected return for ({U}, {P}): expected {expected}, got {actual}");
|
||||
|
||||
let nq = GetMaxQubitCount();
|
||||
AssertIntEqual(nq, 2, $"You are allowed to allocate exactly 2 qubits, and you allocated {nq}");
|
||||
EqualityFactI(nq, 2, $"You are allowed to allocate exactly 2 qubits, and you allocated {nq}");
|
||||
|
||||
let nu = GetOracleCallsCount(Controlled U);
|
||||
AssertIntEqual(nu, 1, $"You are allowed to call Controlled U exactly once, and you called it {nu} times");
|
||||
EqualityFactI(nu, 1, $"You are allowed to call Controlled U exactly once, and you called it {nu} times");
|
||||
}
|
||||
|
||||
operation T21_SingleBitPE_Test () : Unit {
|
||||
|
@ -116,14 +110,14 @@ namespace Quantum.Kata.PhaseEstimation {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation Test2BitPEOnOnePair(U : (Qubit => Unit : Adjoint, Controlled), P : (Qubit => Unit : Adjoint), expected : Double) : Unit {
|
||||
operation Test2BitPEOnOnePair(U : (Qubit => Unit is Adj + Ctl), P : (Qubit => Unit is Adj), expected : Double) : Unit {
|
||||
ResetQubitCount();
|
||||
|
||||
let actual = TwoBitPE(U, P);
|
||||
AssertAlmostEqualTol(actual, expected, 0.001);
|
||||
EqualityWithinToleranceFact(actual, expected, 0.001);
|
||||
|
||||
let nq = GetMaxQubitCount();
|
||||
AssertIntEqual(nq, 2, $"You are allowed to allocate exactly 2 qubits, and you allocated {nq}");
|
||||
EqualityFactI(nq, 2, $"You are allowed to allocate exactly 2 qubits, and you allocated {nq}");
|
||||
}
|
||||
|
||||
operation T22_TwoBitPE_Test () : Unit {
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
namespace Quantum.Kata.QEC_BitFlipCode {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -21,13 +22,9 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
|
||||
|
||||
// Task 2. Encoding Codewords
|
||||
operation Encode_Reference (register : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
ApplyToEachA(CNOT(Head(register), _), Rest(register));
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Encode_Reference (register : Qubit[]) : Unit
|
||||
is Adj {
|
||||
ApplyToEachA(CNOT(Head(register), _), Rest(register));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Quantum.Kata.QEC_BitFlipCode {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
|
||||
namespace Quantum.Kata.QEC_BitFlipCode {
|
||||
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Extensions.Bitwise;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Bitwise;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -29,23 +30,20 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
}
|
||||
|
||||
|
||||
operation StatePrep_Bitmask (qs : Qubit[], bits : Int) : Unit {
|
||||
operation StatePrep_Bitmask (qs : Qubit[], bits : Int) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
if (bits / 4 == 1) {
|
||||
X(qs[0]);
|
||||
}
|
||||
|
||||
if ((bits / 2) % 2 == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
|
||||
if (bits % 2 == 1) {
|
||||
X(qs[2]);
|
||||
}
|
||||
if (bits / 4 == 1) {
|
||||
X(qs[0]);
|
||||
}
|
||||
|
||||
if ((bits / 2) % 2 == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
|
||||
if (bits % 2 == 1) {
|
||||
X(qs[2]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,33 +63,30 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
}
|
||||
|
||||
|
||||
operation StatePrep_TwoBitmasks (qs : Qubit[], bits1 : Int[], bits2 : Int[]) : Unit {
|
||||
operation StatePrep_TwoBitmasks (qs : Qubit[], bits1 : Int[], bits2 : Int[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
|
||||
H(qs[firstDiff]);
|
||||
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
|
||||
H(qs[firstDiff]);
|
||||
|
||||
for (i in 0 .. Length(qs) - 1) {
|
||||
if (bits1[i] == bits2[i]) {
|
||||
if (bits1[i] == 1) {
|
||||
for (i in 0 .. Length(qs) - 1) {
|
||||
if (bits1[i] == bits2[i]) {
|
||||
if (bits1[i] == 1) {
|
||||
X(qs[i]);
|
||||
}
|
||||
} else {
|
||||
if (i > firstDiff) {
|
||||
CNOT(qs[firstDiff], qs[i]);
|
||||
if (bits1[i] != bits1[firstDiff]) {
|
||||
X(qs[i]);
|
||||
}
|
||||
} else {
|
||||
if (i > firstDiff) {
|
||||
CNOT(qs[firstDiff], qs[i]);
|
||||
if (bits1[i] != bits1[firstDiff]) {
|
||||
X(qs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
operation TestParityOnState (statePrep : (Qubit[] => Unit : Adjoint), parity : Int, stateStr : String) : Unit {
|
||||
operation TestParityOnState (statePrep : (Qubit[] => Unit is Adj), parity : Int, stateStr : String) : Unit {
|
||||
|
||||
using (register = Qubit[3]) {
|
||||
// prepare basis state to test on
|
||||
|
@ -99,7 +94,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
let res = MeasureParity(register);
|
||||
|
||||
// check that the returned parity is correct
|
||||
AssertBoolEqual(res == Zero, parity == 0, $"Failed on {stateStr}.");
|
||||
EqualityFactB(res == Zero, parity == 0, $"Failed on {stateStr}.");
|
||||
|
||||
// check that the state has not been modified
|
||||
Adjoint statePrep(register);
|
||||
|
@ -138,9 +133,9 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
operation AssertEqualOnZeroState (
|
||||
statePrep : (Qubit[] => Unit : Adjoint),
|
||||
statePrep : (Qubit[] => Unit is Adj),
|
||||
testImpl : (Qubit[] => Unit),
|
||||
refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
refImpl : (Qubit[] => Unit is Adj)) : Unit {
|
||||
using (qs = Qubit[3]) {
|
||||
// prepare state
|
||||
statePrep(qs);
|
||||
|
@ -158,19 +153,15 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
}
|
||||
|
||||
|
||||
operation StatePrep_Rotate (qs : Qubit[], alpha : Double) : Unit {
|
||||
|
||||
body (...) {
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation StatePrep_Rotate (qs : Qubit[], alpha : Double) : Unit
|
||||
is Adj {
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
}
|
||||
|
||||
|
||||
operation T02_Encode_Test () : Unit {
|
||||
for (i in 0 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
AssertEqualOnZeroState(StatePrep_Rotate(_, alpha), Encode, Encode_Reference);
|
||||
}
|
||||
}
|
||||
|
@ -180,31 +171,28 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
// Task 03
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
operation StatePrep_WithError (qs : Qubit[], alpha : Double, hasError : Bool) : Unit {
|
||||
operation StatePrep_WithError (qs : Qubit[], alpha : Double, hasError : Bool) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
StatePrep_Rotate(qs, alpha);
|
||||
Encode_Reference(qs);
|
||||
StatePrep_Rotate(qs, alpha);
|
||||
Encode_Reference(qs);
|
||||
|
||||
if (hasError) {
|
||||
X(qs[0]);
|
||||
}
|
||||
if (hasError) {
|
||||
X(qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
operation T03_DetectErrorOnLeftQubit_Test () : Unit {
|
||||
using (register = Qubit[3]) {
|
||||
for (i in 0 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
StatePrep_WithError(register, alpha, false);
|
||||
AssertResultEqual(DetectErrorOnLeftQubit(register), Zero, "Failed on a state without X error.");
|
||||
EqualityFactR(DetectErrorOnLeftQubit(register), Zero, "Failed on a state without X error.");
|
||||
Adjoint StatePrep_WithError(register, alpha, false);
|
||||
AssertAllZero(register);
|
||||
StatePrep_WithError(register, alpha, true);
|
||||
AssertResultEqual(DetectErrorOnLeftQubit(register), One, "Failed on a state with X error.");
|
||||
EqualityFactR(DetectErrorOnLeftQubit(register), One, "Failed on a state with X error.");
|
||||
Adjoint StatePrep_WithError(register, alpha, true);
|
||||
AssertAllZero(register);
|
||||
}
|
||||
|
@ -217,7 +205,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
operation BindErrorCorrectionRoundImpl (
|
||||
encoder : (Qubit[] => Unit : Adjoint),
|
||||
encoder : (Qubit[] => Unit is Adj),
|
||||
error : Pauli[],
|
||||
logicalOp : (Qubit[] => Unit),
|
||||
correction : (Qubit[] => Unit),
|
||||
|
@ -246,7 +234,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
|
||||
|
||||
function BindErrorCorrectionRound (
|
||||
encoder : (Qubit[] => Unit : Adjoint),
|
||||
encoder : (Qubit[] => Unit is Adj),
|
||||
error : Pauli[],
|
||||
logicalOp : (Qubit[] => Unit),
|
||||
correction : (Qubit[] => Unit)) : (Qubit[] => Unit) {
|
||||
|
@ -269,7 +257,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
let errors = PauliErrors();
|
||||
|
||||
for (idxError in 0 .. 1) {
|
||||
AssertOperationsEqualReferenced(partialBind(errors[idxError]), NoOp<Qubit[]>, 1);
|
||||
AssertOperationsEqualReferenced(1, partialBind(errors[idxError]), NoOp<Qubit[]>);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +283,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
statePrep(Head(register));
|
||||
Encode_Reference(register);
|
||||
ApplyPauli(errors[idxError], register);
|
||||
AssertIntEqual(DetectErrorOnAnyQubit(register), idxError, $"Failed on state with {errorStr}.");
|
||||
EqualityFactI(DetectErrorOnAnyQubit(register), idxError, $"Failed on state with {errorStr}.");
|
||||
ApplyPauli(errors[idxError], register);
|
||||
Adjoint Encode_Reference(register);
|
||||
Adjoint statePrep(Head(register));
|
||||
|
@ -316,7 +304,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
|
||||
for (idxError in 0 .. Length(errors) - 1) {
|
||||
Message($"Task 06: Testing on {errors[idxError]}...");
|
||||
AssertOperationsEqualReferenced(partialBind(errors[idxError]), NoOp<Qubit[]>, 1);
|
||||
AssertOperationsEqualReferenced(1, partialBind(errors[idxError]), NoOp<Qubit[]>);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,7 +320,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
|
||||
for (idxError in 0 .. Length(errors) - 1) {
|
||||
Message($"Task 07: Testing on {errors[idxError]}...");
|
||||
AssertOperationsEqualReferenced(partialBind(errors[idxError]), ApplyPauli([PauliX], _), 1);
|
||||
AssertOperationsEqualReferenced(1, partialBind(errors[idxError]), ApplyPauli([PauliX], _));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,7 +336,7 @@ namespace Quantum.Kata.QEC_BitFlipCode {
|
|||
|
||||
for (idxError in 0 .. Length(errors) - 1) {
|
||||
Message($"Task 08: Testing on {errors[idxError]}...");
|
||||
AssertOperationsEqualReferenced(partialBind(errors[idxError]), ApplyToEachA(Z, _), 1);
|
||||
AssertOperationsEqualReferenced(1, partialBind(errors[idxError]), ApplyToEachA(Z, _));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Quantum.Kata.SimonsAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -19,69 +19,57 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. f(x) = x₀ ⊕ ... ⊕ xₙ₋₁ (parity of the number of bits set to 1)
|
||||
operation Oracle_CountBits_Reference (x : Qubit[], y : Qubit) : Unit {
|
||||
operation Oracle_CountBits_Reference (x : Qubit[], y : Qubit) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
let N = Length(x);
|
||||
let N = Length(x);
|
||||
|
||||
for (i in 0 .. N - 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
for (i in 0 .. N - 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.2. Bitwise right shift
|
||||
operation Oracle_BitwiseRightShift_Reference (x : Qubit[], y : Qubit[]) : Unit {
|
||||
operation Oracle_BitwiseRightShift_Reference (x : Qubit[], y : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
let N = Length(x);
|
||||
let N = Length(x);
|
||||
|
||||
for (i in 1 .. N - 1) {
|
||||
CNOT(x[i - 1], y[i]);
|
||||
}
|
||||
for (i in 1 .. N - 1) {
|
||||
CNOT(x[i - 1], y[i]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.3. Linear operator
|
||||
operation Oracle_OperatorOutput_Reference (x : Qubit[], y : Qubit, A : Int[]) : Unit {
|
||||
operation Oracle_OperatorOutput_Reference (x : Qubit[], y : Qubit, A : Int[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
let N = Length(x);
|
||||
let N = Length(x);
|
||||
|
||||
for (i in 0 .. N - 1) {
|
||||
if (A[i] == 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
for (i in 0 .. N - 1) {
|
||||
if (A[i] == 1) {
|
||||
CNOT(x[i], y);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.4. Multidimensional linear operator
|
||||
operation Oracle_MultidimensionalOperatorOutput_Reference (x : Qubit[], y : Qubit[], A : Int[][]) : Unit {
|
||||
operation Oracle_MultidimensionalOperatorOutput_Reference (x : Qubit[], y : Qubit[], A : Int[][]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
let N1 = Length(y);
|
||||
let N2 = Length(x);
|
||||
let N1 = Length(y);
|
||||
let N2 = Length(x);
|
||||
|
||||
for (i in 0 .. N1 - 1) {
|
||||
for (j in 0 .. N2 - 1) {
|
||||
if ((A[i])[j] == 1) {
|
||||
CNOT(x[j], y[i]);
|
||||
}
|
||||
for (i in 0 .. N1 - 1) {
|
||||
for (j in 0 .. N2 - 1) {
|
||||
if ((A[i])[j] == 1) {
|
||||
CNOT(x[j], y[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -90,21 +78,15 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. State preparation for Simon's algorithm
|
||||
operation SA_StatePrep_Reference (query : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
ApplyToEachA(H, query);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation SA_StatePrep_Reference (query : Qubit[]) : Unit
|
||||
is Adj {
|
||||
ApplyToEachA(H, query);
|
||||
}
|
||||
|
||||
|
||||
// Task 2.2. Quantum part of Simon's algorithm
|
||||
operation Simon_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit[]) => Unit)) : Int[] {
|
||||
|
||||
mutable j = new Int[N];
|
||||
|
||||
|
||||
// allocate input and answer registers with N qubits each
|
||||
using ((x, y) = (Qubit[N], Qubit[N])) {
|
||||
// prepare qubits in the right state
|
||||
|
@ -118,18 +100,18 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
|
||||
// measure all qubits of the input register;
|
||||
// the result of each measurement is converted to an Int
|
||||
mutable j = new Int[N];
|
||||
for (i in 0 .. N - 1) {
|
||||
if (M(x[i]) == One) {
|
||||
set j[i] = 1;
|
||||
set j w/= i <- 1;
|
||||
}
|
||||
}
|
||||
|
||||
// before releasing the qubits make sure they are all in |0⟩ states
|
||||
ResetAll(x);
|
||||
ResetAll(y);
|
||||
return j;
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
namespace Quantum.Kata.SimonsAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -29,13 +30,9 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
// 1) N qubits in an arbitrary state |x⟩
|
||||
// 2) a qubit in an arbitrary state |y⟩
|
||||
// Goal: Transform state |x, y⟩ into |x, y ⊕ x_0 ⊕ x_1 ... ⊕ x_{n-1}⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_CountBits (x : Qubit[], y : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_CountBits (x : Qubit[], y : Qubit) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,13 +42,9 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
// 2) N qubits in an arbitrary state |y⟩
|
||||
// Goal: Transform state |x, y⟩ into |x, y ⊕ f(x)⟩, where f is bitwise right shift function, i.e.,
|
||||
// |y ⊕ f(x)⟩ = |y_0, y_1 ⊕ x_0, y_2 ⊕ x_1, ..., y_{n-1} ⊕ x_{n-2}⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_BitwiseRightShift (x : Qubit[], y : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Oracle_BitwiseRightShift (x : Qubit[], y : Qubit[]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,17 +55,14 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
// 3) a 1xN binary matrix (represented as an Int[]) describing operator A
|
||||
// (see https://en.wikipedia.org/wiki/Transformation_matrix )
|
||||
// Goal: Transform state |x, y⟩ into |x, y ⊕ A(x) ⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_OperatorOutput (x : Qubit[], y : Qubit, A : Int[]) : Unit {
|
||||
operation Oracle_OperatorOutput (x : Qubit[], y : Qubit, A : Int[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(x), Length(A), "Arrays x and A should have the same length");
|
||||
// The following line enforces the constraint on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
EqualityFactI(Length(x), Length(A), "Arrays x and A should have the same length");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -86,18 +76,15 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
// the second dimension (columns) - the input register,
|
||||
// i.e., A[r][c] (element in r-th row and c-th column) corresponds to x[c] and y[r].
|
||||
// Goal: Transform state |x, y⟩ into |x, y ⊕ A(x) ⟩ (⊕ is addition modulo 2).
|
||||
operation Oracle_MultidimensionalOperatorOutput (x : Qubit[], y : Qubit[], A : Int[][]) : Unit {
|
||||
operation Oracle_MultidimensionalOperatorOutput (x : Qubit[], y : Qubit[], A : Int[][]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// The following lines enforce the constraints on the input arrays.
|
||||
// You don't need to modify it. Feel free to remove it, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(x), Length(A[0]), "Arrays x and A[0] should have the same length");
|
||||
AssertIntEqual(Length(y), Length(A), "Arrays y and A should have the same length");
|
||||
// The following lines enforce the constraints on the input arrays.
|
||||
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
|
||||
EqualityFactI(Length(x), Length(A[0]), "Arrays x and A[0] should have the same length");
|
||||
EqualityFactI(Length(y), Length(A), "Arrays y and A should have the same length");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,13 +97,9 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
// 1) N qubits in |0⟩ state (query register)
|
||||
// Goal: create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩ on query register
|
||||
// (i.e. the state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N)).
|
||||
operation SA_StatePrep (query : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation SA_StatePrep (query : Qubit[]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,7 +126,7 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
operation Simon_Algorithm (N : Int, Uf : ((Qubit[], Qubit[]) => Unit)) : Int[] {
|
||||
|
||||
// Declare an Int array in which the result will be stored;
|
||||
// the array has to be mutable to allow updating its elements.
|
||||
// the variable has to be mutable to allow updating it.
|
||||
mutable b = new Int[N];
|
||||
|
||||
// ...
|
||||
|
|
|
@ -46,20 +46,18 @@ namespace Q22
|
|||
|
||||
public BooleanVector Kernel => new BooleanVector(kernel);
|
||||
|
||||
public QArray<QArray<long>> Transformation => new QArray<QArray<long>>(
|
||||
public IQArray<IQArray<long>> Transformation => new QArray<IQArray<long>>(
|
||||
transformation.Select(
|
||||
vector => new QArray<long>(vector)));
|
||||
|
||||
public QArray<QArray<long>> ExtendedTransformation
|
||||
public IQArray<IQArray<long>> ExtendedTransformation
|
||||
{
|
||||
get
|
||||
{
|
||||
var array = new QArray<QArray<long>>(
|
||||
transformation.Select(
|
||||
vector => new QArray<long>(vector)))
|
||||
{
|
||||
new QArray<long>(transformation.Last())
|
||||
};
|
||||
var array = (IQArray<IQArray<long>>)new QArray<IQArray<long>>(
|
||||
transformation.Select(vector => new QArray<long>(vector))
|
||||
);
|
||||
array = QArray<IQArray<long>>.Add (array, new QArray<IQArray<long>>(new QArray<long>(transformation.Last())));
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +112,7 @@ namespace Q22
|
|||
var sim = new OracleCounterSimulator();
|
||||
|
||||
var len = instance.Kernel.Count;
|
||||
var saver = new List<QArray<long>>();
|
||||
var saver = new List<IQArray<long>>();
|
||||
|
||||
for (int i = 0; i < len * 4; ++i)
|
||||
{
|
||||
|
|
|
@ -9,44 +9,36 @@
|
|||
|
||||
namespace Quantum.Kata.SimonsAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
|
||||
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
oracle(qs[0 .. N - 2], qs[N - 1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit is Adj)) : Unit
|
||||
is Adj {
|
||||
let N = Length(qs);
|
||||
oracle(qs[0 .. N - 2], qs[N - 1]);
|
||||
}
|
||||
|
||||
|
||||
operation ApplyOracleWithOutputArrA (qs : Qubit[], oracle : ((Qubit[], Qubit[]) => Unit : Adjoint), outputSize : Int) : Unit {
|
||||
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
oracle(qs[0 .. (N - 1) - outputSize], qs[N - outputSize .. N - 1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation ApplyOracleWithOutputArrA (qs : Qubit[], oracle : ((Qubit[], Qubit[]) => Unit is Adj), outputSize : Int) : Unit
|
||||
is Adj {
|
||||
let N = Length(qs);
|
||||
oracle(qs[0 .. (N - 1) - outputSize], qs[N - outputSize .. N - 1]);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation AssertTwoOraclesAreEqual (
|
||||
nQubits : Range,
|
||||
oracle1 : ((Qubit[], Qubit) => Unit : Adjoint),
|
||||
oracle2 : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
|
||||
oracle1 : ((Qubit[], Qubit) => Unit is Adj),
|
||||
oracle2 : ((Qubit[], Qubit) => Unit is Adj)) : Unit {
|
||||
let sol = ApplyOracleA(_, oracle1);
|
||||
let refSol = ApplyOracleA(_, oracle2);
|
||||
|
||||
for (i in nQubits) {
|
||||
AssertOperationsEqualReferenced(sol, refSol, i + 1);
|
||||
AssertOperationsEqualReferenced(i+1, sol, refSol);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,11 +46,11 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
operation AssertTwoOraclesWithOutputArrAreEqual (
|
||||
inputSize : Int,
|
||||
outputSize : Int,
|
||||
oracle1 : ((Qubit[], Qubit[]) => Unit : Adjoint),
|
||||
oracle2 : ((Qubit[], Qubit[]) => Unit : Adjoint)) : Unit {
|
||||
oracle1 : ((Qubit[], Qubit[]) => Unit is Adj),
|
||||
oracle2 : ((Qubit[], Qubit[]) => Unit is Adj)) : Unit {
|
||||
let sol = ApplyOracleWithOutputArrA(_, oracle1, outputSize);
|
||||
let refSol = ApplyOracleWithOutputArrA(_, oracle2, outputSize);
|
||||
AssertOperationsEqualReferenced(sol, refSol, inputSize + outputSize);
|
||||
AssertOperationsEqualReferenced(inputSize + outputSize, sol, refSol);
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,7 +69,7 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation AssertTwoOraclesWithIntArrAreEqual (A : Int[], oracle1 : ((Qubit[], Qubit, Int[]) => Unit : Adjoint), oracle2 : ((Qubit[], Qubit, Int[]) => Unit : Adjoint)) : Unit {
|
||||
operation AssertTwoOraclesWithIntArrAreEqual (A : Int[], oracle1 : ((Qubit[], Qubit, Int[]) => Unit is Adj), oracle2 : ((Qubit[], Qubit, Int[]) => Unit is Adj)) : Unit {
|
||||
AssertTwoOraclesAreEqual(Length(A) .. Length(A), oracle1(_, _, A), oracle2(_, _, A));
|
||||
}
|
||||
|
||||
|
@ -109,8 +101,8 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
// ------------------------------------------------------
|
||||
operation AssertTwoOraclesWithIntMatrixAreEqual (
|
||||
A : Int[][],
|
||||
oracle1 : ((Qubit[], Qubit[], Int[][]) => Unit : Adjoint),
|
||||
oracle2 : ((Qubit[], Qubit[], Int[][]) => Unit : Adjoint)) : Unit {
|
||||
oracle1 : ((Qubit[], Qubit[], Int[][]) => Unit is Adj),
|
||||
oracle2 : ((Qubit[], Qubit[], Int[][]) => Unit is Adj)) : Unit {
|
||||
let inputSize = Length(A[0]);
|
||||
let outputSize = Length(A);
|
||||
AssertTwoOraclesWithOutputArrAreEqual(inputSize, outputSize, oracle1(_, _, A), oracle2(_, _, A));
|
||||
|
@ -119,11 +111,11 @@ namespace Quantum.Kata.SimonsAlgorithm {
|
|||
|
||||
operation AssertTwoOraclesWithDifferentOutputsAreEqual (
|
||||
inputSize : Int,
|
||||
oracle1 : ((Qubit[], Qubit[]) => Unit : Adjoint),
|
||||
oracle2 : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
|
||||
oracle1 : ((Qubit[], Qubit[]) => Unit is Adj),
|
||||
oracle2 : ((Qubit[], Qubit) => Unit is Adj)) : Unit {
|
||||
let sol = ApplyOracleWithOutputArrA(_, oracle1, 1);
|
||||
let refSol = ApplyOracleA(_, oracle2);
|
||||
AssertOperationsEqualReferenced(sol, refSol, inputSize + 1);
|
||||
AssertOperationsEqualReferenced(inputSize + 1, sol, refSol);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace Quantum.Kata.GroversAlgorithm
|
|||
return base.Apply();
|
||||
}
|
||||
|
||||
public override QArray<Qubit> Apply(long count)
|
||||
public override IQArray<Qubit> Apply(long count)
|
||||
{
|
||||
_sim._qubitsAllocated += count;
|
||||
if (_sim._qubitsAllocated > _sim._maxQubitsAllocated)
|
||||
|
@ -140,7 +140,7 @@ namespace Quantum.Kata.GroversAlgorithm
|
|||
base.Apply(q);
|
||||
}
|
||||
|
||||
public override void Apply(QArray<Qubit> qubits)
|
||||
public override void Apply(IQArray<Qubit> qubits)
|
||||
{
|
||||
_sim._qubitsAllocated -= qubits.Length;
|
||||
base.Apply(qubits);
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
|
||||
namespace Quantum.Kata.GroversAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Measurement;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
@ -21,160 +23,123 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. The AND oracle: f(x) = x₀ ∧ x₁
|
||||
operation Oracle_And_Reference_2 (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
CCNOT(queryRegister[0], queryRegister[1], target);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_And_Reference_2 (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
CCNOT(queryRegister[0], queryRegister[1], target);
|
||||
}
|
||||
|
||||
// AND oracle for an arbitrary number of qubits in query register
|
||||
operation Oracle_And_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
Controlled X(queryRegister, target);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_And_Reference (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
Controlled X(queryRegister, target);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Task 1.2. The OR oracle: f(x) = x₀ ∨ x₁
|
||||
operation Oracle_Or_Reference_2 (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// x₀ ∨ x₁ = ¬ (¬x₀ ∧ ¬x₁)
|
||||
// First, flip target if both qubits are in |0⟩ state
|
||||
X(queryRegister[0]);
|
||||
X(queryRegister[1]);
|
||||
CCNOT(queryRegister[0], queryRegister[1], target);
|
||||
// Return query register to the starting state
|
||||
X(queryRegister[0]);
|
||||
X(queryRegister[1]);
|
||||
// Then flip target again to get negation
|
||||
X(target);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_Or_Reference_2 (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
// x₀ ∨ x₁ = ¬ (¬x₀ ∧ ¬x₁)
|
||||
// First, flip target if both qubits are in |0⟩ state
|
||||
X(queryRegister[0]);
|
||||
X(queryRegister[1]);
|
||||
CCNOT(queryRegister[0], queryRegister[1], target);
|
||||
// Return query register to the starting state
|
||||
X(queryRegister[0]);
|
||||
X(queryRegister[1]);
|
||||
// Then flip target again to get negation
|
||||
X(target);
|
||||
}
|
||||
|
||||
// OR oracle for an arbitrary number of qubits in query register
|
||||
operation Oracle_Or_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// x₀ ∨ x₁ = ¬ (¬x₀ ∧ ¬x₁)
|
||||
// First, flip target if both qubits are in |0⟩ state
|
||||
(ControlledOnInt(0, X))(queryRegister, target);
|
||||
// Then flip target again to get negation
|
||||
X(target);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_Or_Reference (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
// x₀ ∨ x₁ = ¬ (¬x₀ ∧ ¬x₁)
|
||||
// First, flip target if both qubits are in |0⟩ state
|
||||
(ControlledOnInt(0, X))(queryRegister, target);
|
||||
// Then flip target again to get negation
|
||||
X(target);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Task 1.3. The XOR oracle: f(x) = x₀ ⊕ x₁
|
||||
operation Oracle_Xor_Reference_2 (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
CNOT(queryRegister[0], target);
|
||||
CNOT(queryRegister[1], target);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_Xor_Reference_2 (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
CNOT(queryRegister[0], target);
|
||||
CNOT(queryRegister[1], target);
|
||||
}
|
||||
|
||||
// XOR oracle for an arbitrary number of qubits in query register
|
||||
operation Oracle_Xor_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
ApplyToEachA(CNOT(_, target), queryRegister);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_Xor_Reference (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
ApplyToEachA(CNOT(_, target), queryRegister);
|
||||
}
|
||||
|
||||
// Alternative solution to task 1.3, based on representation as a 2-SAT problem
|
||||
operation Oracle_Xor_2SAT (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// x₀ ⊕ x₁ = (x₀ ∨ x₁) ∧ (¬x₀ ∨ ¬x₁)
|
||||
// Allocate 2 ancilla qubits to store results of clause evaluation
|
||||
using ((a1, a2) = (Qubit(), Qubit())) {
|
||||
// The first clause is exactly the Or oracle
|
||||
Oracle_Or_Reference(queryRegister, a1);
|
||||
// The second clause is the Or oracle, applied to negations of the variables
|
||||
WithA(ApplyToEachA(X, _), Oracle_Or_Reference(_, a2), queryRegister);
|
||||
// To calculate the final answer, apply the And oracle with the ancilla qubits as inputs
|
||||
Oracle_And_Reference([a1, a2], target);
|
||||
// Uncompute the values of the ancillas before releasing them (no measuring!)
|
||||
Adjoint WithA(ApplyToEachA(X, _), Oracle_Or_Reference(_, a2), queryRegister);
|
||||
Adjoint Oracle_Or_Reference(queryRegister, a1);
|
||||
}
|
||||
operation Oracle_Xor_2SAT (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
// x₀ ⊕ x₁ = (x₀ ∨ x₁) ∧ (¬x₀ ∨ ¬x₁)
|
||||
// Allocate 2 auxillary qubits to store results of clause evaluation
|
||||
using ((a1, a2) = (Qubit(), Qubit())) {
|
||||
// The first clause is exactly the Or oracle
|
||||
Oracle_Or_Reference(queryRegister, a1);
|
||||
// The second clause is the Or oracle, applied to negations of the variables
|
||||
WithA(ApplyToEachA(X, _), Oracle_Or_Reference(_, a2), queryRegister);
|
||||
// To calculate the final answer, apply the And oracle with the ancilla qubits as inputs
|
||||
Oracle_And_Reference([a1, a2], target);
|
||||
// Uncompute the values of the ancillas before releasing them (no measuring!)
|
||||
Adjoint WithA(ApplyToEachA(X, _), Oracle_Or_Reference(_, a2), queryRegister);
|
||||
Adjoint Oracle_Or_Reference(queryRegister, a1);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Task 1.4. Alternating bits oracle: f(x) = (x₀ ⊕ x₁) ∧ (x₁ ⊕ x₂) ∧ ... ∧ (xₙ₋₂ ⊕ xₙ₋₁)
|
||||
operation Oracle_AlternatingBits_Reference (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
operation Oracle_AlternatingBits_Reference (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// Allocate N-1 qubits to store results of clauses evaluation
|
||||
let N = Length(queryRegister);
|
||||
using (anc = Qubit[N-1]) {
|
||||
// Evaluate all XOR clauses (using XOR oracle)
|
||||
for (i in 0..N-2) {
|
||||
Oracle_Xor_Reference(queryRegister[i..i+1], anc[i]);
|
||||
}
|
||||
// Allocate N-1 qubits to store results of clauses evaluation
|
||||
let N = Length(queryRegister);
|
||||
using (anc = Qubit[N-1]) {
|
||||
// Evaluate all XOR clauses (using XOR oracle)
|
||||
for (i in 0..N-2) {
|
||||
Oracle_Xor_Reference(queryRegister[i..i+1], anc[i]);
|
||||
}
|
||||
|
||||
// Evaluate the overall formula as an AND oracle (can use reference depending on the implementation)
|
||||
Controlled X(anc, target);
|
||||
// Evaluate the overall formula as an AND oracle (can use reference depending on the implementation)
|
||||
Controlled X(anc, target);
|
||||
|
||||
// Uncompute
|
||||
for (i in 0..N-2) {
|
||||
Adjoint Oracle_Xor_Reference(queryRegister[i..i+1], anc[i]);
|
||||
}
|
||||
// Uncompute
|
||||
for (i in 0..N-2) {
|
||||
Adjoint Oracle_Xor_Reference(queryRegister[i..i+1], anc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
// Answer-based solution for alternating bits oracle
|
||||
operation FlipAlternatingPositionBits_Reference (register : Qubit[], firstIndex : Int) : Unit {
|
||||
operation FlipAlternatingPositionBits_Reference (register : Qubit[], firstIndex : Int) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// iterate over elements in every second position, starting with firstIndex (indexes are 0-based)
|
||||
for (i in firstIndex .. 2 .. Length(register) - 1) {
|
||||
X(register[i]);
|
||||
}
|
||||
// iterate over elements in every second position, starting with firstIndex (indexes are 0-based)
|
||||
for (i in firstIndex .. 2 .. Length(register) - 1) {
|
||||
X(register[i]);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
operation Oracle_AlternatingBits_Answer (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
operation Oracle_AlternatingBits_Answer (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// similar to task 1.2 from GroversAlgorithm kata:
|
||||
// first mark the state with 1s in even positions (starting with the first qubit, index 0),
|
||||
// then mark the state with 1s in odd positions
|
||||
for (firstIndex in 0..1) {
|
||||
FlipAlternatingPositionBits_Reference(queryRegister, firstIndex);
|
||||
Controlled X(queryRegister, target);
|
||||
Adjoint FlipAlternatingPositionBits_Reference(queryRegister, firstIndex);
|
||||
}
|
||||
// similar to task 1.2 from GroversAlgorithm kata:
|
||||
// first mark the state with 1s in even positions (starting with the first qubit, index 0),
|
||||
// then mark the state with 1s in odd positions
|
||||
for (firstIndex in 0..1) {
|
||||
FlipAlternatingPositionBits_Reference(queryRegister, firstIndex);
|
||||
Controlled X(queryRegister, target);
|
||||
Adjoint FlipAlternatingPositionBits_Reference(queryRegister, firstIndex);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
@ -191,9 +156,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
let (index, isTrue) = clause[varIndex];
|
||||
// Add the variable used in the clause to the list of variables which we'll need to call the OR oracle
|
||||
let qt = queryRegister[index];
|
||||
set qubits[varIndex] = queryRegister[index];
|
||||
set qubits w/= varIndex <- queryRegister[index];
|
||||
// If the negation of the variable is present in the formula, mark the qubit as needing a flip
|
||||
set flip[varIndex] = not isTrue;
|
||||
set flip w/= varIndex <- not isTrue;
|
||||
}
|
||||
|
||||
// Actually calculate the clause (flip the necessary qubits, call OR oracle, flip them back)
|
||||
|
@ -207,14 +172,10 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Task 1.5. 2-SAT problem oracle: f(x) = ∧ᵢ (yᵢ₀ ∨ yᵢ₁), yᵢₖ = either xᵢₖ or ¬xᵢₖ
|
||||
operation Oracle_2SAT_Reference (queryRegister : Qubit[],
|
||||
target : Qubit,
|
||||
problem : (Int, Bool)[][]) : Unit {
|
||||
|
||||
body (...) {
|
||||
problem : (Int, Bool)[][]) : Unit
|
||||
is Adj {
|
||||
// This is exactly the upcoming task 1.6, so using the general SAT oracle
|
||||
Oracle_SAT_Reference(queryRegister, target, problem);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
|
@ -222,18 +183,15 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Task 1.6. General SAT problem oracle: f(x) = ∧ᵢ (∨ₖ yᵢₖ), yᵢₖ = either xᵢₖ or ¬xᵢₖ
|
||||
operation Oracle_SAT_Reference (queryRegister : Qubit[],
|
||||
target : Qubit,
|
||||
problem : (Int, Bool)[][]) : Unit {
|
||||
problem : (Int, Bool)[][]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// Similar to task 1.4.
|
||||
// Allocate qubits to store results of clauses evaluation
|
||||
using (anc = Qubit[Length(problem)]) {
|
||||
// Compute clauses, evaluate the overall formula as an AND oracle (can use reference depending on the implementation) and uncompute
|
||||
WithA(EvaluateOrClauses(queryRegister, _, problem), Controlled X(_, target), anc);
|
||||
}
|
||||
// Similar to task 1.4.
|
||||
// Allocate qubits to store results of clauses evaluation
|
||||
using (anc = Qubit[Length(problem)]) {
|
||||
// Compute clauses, evaluate the overall formula as an AND oracle (can use reference depending on the implementation) and uncompute
|
||||
WithA(EvaluateOrClauses(queryRegister, _, problem), Controlled X(_, target), anc);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
|
@ -241,30 +199,29 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Part II. Using Grover's algorithm for problems with multiple solutions
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
operation OracleConverterImpl_Reference (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint), register : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
using (target = Qubit()) {
|
||||
// Put the target into the |-⟩ state
|
||||
X(target);
|
||||
H(target);
|
||||
operation OracleConverterImpl_Reference (markingOracle : ((Qubit[], Qubit) => Unit is Adj), register : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
using (target = Qubit()) {
|
||||
// Put the target into the |-⟩ state
|
||||
X(target);
|
||||
H(target);
|
||||
|
||||
// Apply the marking oracle; since the target is in the |-⟩ state,
|
||||
// flipping the target if the register satisfies the oracle condition will apply a -1 factor to the state
|
||||
markingOracle(register, target);
|
||||
// Apply the marking oracle; since the target is in the |-⟩ state,
|
||||
// flipping the target if the register satisfies the oracle condition will apply a -1 factor to the state
|
||||
markingOracle(register, target);
|
||||
|
||||
// Put the target back into |0⟩ so we can return it
|
||||
H(target);
|
||||
X(target);
|
||||
}
|
||||
// Put the target back into |0⟩ so we can return it
|
||||
H(target);
|
||||
X(target);
|
||||
}
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
function OracleConverter_Reference (markingOracle : ((Qubit[], Qubit) => Unit : Adjoint)) : (Qubit[] => Unit : Adjoint) {
|
||||
function OracleConverter_Reference (markingOracle : ((Qubit[], Qubit) => Unit is Adj)) : (Qubit[] => Unit is Adj) {
|
||||
return OracleConverterImpl_Reference(markingOracle, _);
|
||||
}
|
||||
|
||||
operation GroversAlgorithm_Loop (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint), iterations : Int) : Unit {
|
||||
operation GroversAlgorithm_Loop (register : Qubit[], oracle : ((Qubit[], Qubit) => Unit is Adj), iterations : Int) : Unit {
|
||||
let phaseOracle = OracleConverter_Reference(oracle);
|
||||
ApplyToEach(H, register);
|
||||
|
||||
|
@ -280,7 +237,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
|
||||
|
||||
// Task 2.2. Universal implementation of Grover's algorithm
|
||||
operation GroversAlgorithm_Reference (N : Int, oracle : ((Qubit[], Qubit) => Unit : Adjoint)) : Bool[] {
|
||||
operation GroversAlgorithm_Reference (N : Int, oracle : ((Qubit[], Qubit) => Unit is Adj)) : Bool[] {
|
||||
// In this task you don't know the optimal number of iterations upfront,
|
||||
// so it makes sense to try different numbers of iterations.
|
||||
// This way, even if you don't hit the "correct" number of iterations on one of your tries,
|
||||
|
@ -305,7 +262,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
ResetAll(register);
|
||||
} until (correct or iter > 100) // the fail-safe to avoid going into an infinite loop
|
||||
fixup {
|
||||
set iter = iter * 2;
|
||||
set iter *= 2;
|
||||
}
|
||||
if (not correct) {
|
||||
fail "Failed to find an answer";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
namespace Quantum.Kata.GroversAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
@ -47,13 +48,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Leave the query register in the same state it started in.
|
||||
// Stretch goal: Can you implement the oracle so that it would work
|
||||
// for queryRegister containing an arbitrary number of qubits?
|
||||
operation Oracle_And (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_And (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -67,13 +64,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Leave the query register in the same state it started in.
|
||||
// Stretch goal: Can you implement the oracle so that it would work
|
||||
// for queryRegister containing an arbitrary number of qubits?
|
||||
operation Oracle_Or (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_Or (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,13 +80,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Leave the query register in the same state it started in.
|
||||
// Stretch goal: Can you implement the oracle so that it would work
|
||||
// for queryRegister containing an arbitrary number of qubits?
|
||||
operation Oracle_Xor (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_Xor (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,13 +97,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// |10101...⟩ and |01010...⟩
|
||||
// It is possible (and quite straightforward) to implement this oracle based on this observation;
|
||||
// however, for the purposes of learning to write oracles to solve SAT problems we recommend using the representation above.
|
||||
operation Oracle_AlternatingBits (queryRegister : Qubit[], target : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
operation Oracle_AlternatingBits (queryRegister : Qubit[], target : Qubit) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -149,13 +134,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Leave the query register in the same state it started in.
|
||||
operation Oracle_2SAT (queryRegister : Qubit[],
|
||||
target : Qubit,
|
||||
problem : (Int, Bool)[][]) : Unit {
|
||||
|
||||
body (...) {
|
||||
problem : (Int, Bool)[][]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
|
@ -183,13 +164,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// Leave the query register in the same state it started in.
|
||||
operation Oracle_SAT (queryRegister : Qubit[],
|
||||
target : Qubit,
|
||||
problem : (Int, Bool)[][]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// ...
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
problem : (Int, Bool)[][]) : Unit
|
||||
is Adj {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
|
@ -227,7 +204,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
// in a way that would be robust to accidental failures, but you knew the optimal number of iterations
|
||||
// (the number that minimizes the probability of such failure).
|
||||
// In this task you also need to make your implementation robust to not knowing the optimal number of iterations.
|
||||
operation GroversAlgorithm (N : Int, oracle : ((Qubit[], Qubit) => Unit : Adjoint)) : Bool[] {
|
||||
operation GroversAlgorithm (N : Int, oracle : ((Qubit[], Qubit) => Unit is Adj)) : Bool[] {
|
||||
// ...
|
||||
return new Bool[N];
|
||||
}
|
||||
|
|
|
@ -9,30 +9,27 @@
|
|||
|
||||
namespace Quantum.Kata.GroversAlgorithm {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// helper wrapper to represent oracle operation on input and output registers as an operation on an array of qubits
|
||||
operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit) => Unit : Adjoint), qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
op(Most(qs), Tail(qs));
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit) => Unit is Adj), qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
op(Most(qs), Tail(qs));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// helper wrapper to test for operation equality on various register sizes
|
||||
operation AssertRegisterOperationsEqual (testOp : (Qubit[] => Unit), refOp : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
operation AssertRegisterOperationsEqual (testOp : (Qubit[] => Unit), refOp : (Qubit[] => Unit is Adj)) : Unit {
|
||||
for (n in 2 .. 10) {
|
||||
AssertOperationsEqualReferenced(testOp, refOp, n);
|
||||
AssertOperationsEqualReferenced(n, testOp, refOp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +74,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
|
||||
let testOp = QubitArrayWrapperOperation(Oracle_And, _);
|
||||
let refOp = QubitArrayWrapperOperation(Oracle_And_Reference, _);
|
||||
AssertOperationsEqualReferenced(testOp, refOp, 3);
|
||||
AssertOperationsEqualReferenced(3, testOp, refOp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,7 +88,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
|
||||
let testOp = QubitArrayWrapperOperation(Oracle_Or, _);
|
||||
let refOp = QubitArrayWrapperOperation(Oracle_Or_Reference, _);
|
||||
AssertOperationsEqualReferenced(testOp, refOp, 3);
|
||||
AssertOperationsEqualReferenced(3, testOp, refOp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -105,7 +102,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
|
||||
let testOp = QubitArrayWrapperOperation(Oracle_Xor, _);
|
||||
let refOp = QubitArrayWrapperOperation(Oracle_Xor_Reference, _);
|
||||
AssertOperationsEqualReferenced(testOp, refOp, 3);
|
||||
AssertOperationsEqualReferenced(3, testOp, refOp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,7 +123,7 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
for (n in 2 .. 5) {
|
||||
AssertOracleImplementsFunction(n, Oracle_AlternatingBits, AlternatingBits);
|
||||
|
||||
AssertOperationsEqualReferenced(testOp, refOp, n + 1);
|
||||
AssertOperationsEqualReferenced(n + 1, testOp, refOp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,12 +150,14 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
let nVar = RandomInt(5) + 3;
|
||||
let nClause = RandomInt(2 * nVar) + 1;
|
||||
mutable problem = new (Int, Bool)[][nClause];
|
||||
|
||||
for (j in 0..nClause-1) {
|
||||
mutable nVarInClause = is2SAT ? 2 | (RandomInt(4) + 1);
|
||||
if (nVarInClause > nVar) {
|
||||
set nVarInClause = nVar;
|
||||
}
|
||||
set problem[j] = new (Int, Bool)[nVarInClause];
|
||||
|
||||
mutable problemRow = new (Int, Bool)[nVarInClause];
|
||||
mutable usedVariables = new Bool[nVar];
|
||||
// Make sure variables in each clause are distinct
|
||||
for (k in 0..nVarInClause-1) {
|
||||
|
@ -167,32 +166,30 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
set nextInd = RandomInt(nVar);
|
||||
} until (not usedVariables[nextInd])
|
||||
fixup {}
|
||||
set problem[j][k] = (nextInd, RandomInt(2) > 0);
|
||||
set usedVariables[nextInd] = true;
|
||||
set problemRow w/= k <- (nextInd, RandomInt(2) > 0);
|
||||
set usedVariables w/= nextInd <- true;
|
||||
}
|
||||
set problem w/= j <- problemRow;
|
||||
}
|
||||
return (nVar, problem);
|
||||
}
|
||||
|
||||
operation Run2SATTests (oracle : ((Qubit[], Qubit, (Int, Bool)[][]) => Unit : Adjoint)) : Unit {
|
||||
operation Run2SATTests (oracle : ((Qubit[], Qubit, (Int, Bool)[][]) => Unit is Adj)) : Unit {
|
||||
// Cross-tests:
|
||||
// OR oracle
|
||||
AssertOperationsEqualReferenced(
|
||||
AssertOperationsEqualReferenced(3,
|
||||
QubitArrayWrapperOperation(oracle(_, _, [[(0, true), (1, true)]]), _),
|
||||
QubitArrayWrapperOperation(Oracle_Or_Reference, _),
|
||||
3);
|
||||
QubitArrayWrapperOperation(Oracle_Or_Reference, _));
|
||||
|
||||
// XOR oracle
|
||||
AssertOperationsEqualReferenced(
|
||||
AssertOperationsEqualReferenced(3,
|
||||
QubitArrayWrapperOperation(oracle(_, _, [[(0, true), (1, true)], [(1, false), (0, false)]]), _),
|
||||
QubitArrayWrapperOperation(Oracle_Xor_Reference, _),
|
||||
3);
|
||||
QubitArrayWrapperOperation(Oracle_Xor_Reference, _));
|
||||
|
||||
// AlternatingBits oracle for 3 qubits
|
||||
AssertOperationsEqualReferenced(
|
||||
AssertOperationsEqualReferenced(4,
|
||||
QubitArrayWrapperOperation(oracle(_, _, [[(1, false), (2, false)], [(0, true), (1, true)], [(1, false), (0, false)], [(2, true), (1, true)]]), _),
|
||||
QubitArrayWrapperOperation(Oracle_AlternatingBits_Reference, _),
|
||||
4);
|
||||
QubitArrayWrapperOperation(Oracle_AlternatingBits_Reference, _));
|
||||
|
||||
// Standalone tests
|
||||
for (i in 1..10) {
|
||||
|
@ -201,10 +198,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
|
||||
AssertOracleImplementsFunction(nVar, oracle(_, _, problem), F_SAT(_, problem));
|
||||
|
||||
AssertOperationsEqualReferenced(
|
||||
AssertOperationsEqualReferenced(nVar + 1,
|
||||
QubitArrayWrapperOperation(oracle(_, _, problem), _),
|
||||
QubitArrayWrapperOperation(Oracle_SAT_Reference(_, _, problem), _),
|
||||
nVar + 1
|
||||
QubitArrayWrapperOperation(Oracle_SAT_Reference(_, _, problem), _)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -226,10 +222,9 @@ namespace Quantum.Kata.GroversAlgorithm {
|
|||
|
||||
AssertOracleImplementsFunction(nVar, Oracle_SAT(_, _, problem), F_SAT(_, problem));
|
||||
|
||||
AssertOperationsEqualReferenced(
|
||||
AssertOperationsEqualReferenced(nVar + 1,
|
||||
QubitArrayWrapperOperation(Oracle_SAT(_, _, problem), _),
|
||||
QubitArrayWrapperOperation(Oracle_SAT_Reference(_, _, problem), _),
|
||||
nVar + 1
|
||||
QubitArrayWrapperOperation(Oracle_SAT_Reference(_, _, problem), _)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,31 +10,28 @@
|
|||
|
||||
namespace Quantum.Kata.SuperdenseCoding {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
// Task 1. Entangled pair
|
||||
operation CreateEntangledPair_Reference (qs : Qubit[]) : Unit {
|
||||
operation CreateEntangledPair_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// The easiest way to create an entangled pair is to start with
|
||||
// applying a Hadamard transformation to one of the qubits:
|
||||
H(qs[0]);
|
||||
// The easiest way to create an entangled pair is to start with
|
||||
// applying a Hadamard transformation to one of the qubits:
|
||||
H(qs[0]);
|
||||
|
||||
// This has left us in state:
|
||||
// ((|0⟩ + |1⟩) / sqrt(2)) ⊗ |0⟩
|
||||
// This has left us in state:
|
||||
// ((|0⟩ + |1⟩) / sqrt(2)) ⊗ |0⟩
|
||||
|
||||
// Now, if we flip the second qubit conditioned on the state
|
||||
// of the first one, we get that the states of the two qubits will always match.
|
||||
CNOT(qs[0], qs[1]);
|
||||
// So we ended up in the state:
|
||||
// (|00⟩ + |11⟩) / sqrt(2)
|
||||
//
|
||||
// Which is the required Bell pair |Φ⁺⟩
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// Now, if we flip the second qubit conditioned on the state
|
||||
// of the first one, we get that the states of the two qubits will always match.
|
||||
CNOT(qs[0], qs[1]);
|
||||
// So we ended up in the state:
|
||||
// (|00⟩ + |11⟩) / sqrt(2)
|
||||
//
|
||||
// Which is the required Bell pair |Φ⁺⟩
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,9 +59,6 @@ namespace Quantum.Kata.SuperdenseCoding {
|
|||
|
||||
// Task 3. Decode the message (Bob's task)
|
||||
operation DecodeMessageFromQubits_Reference (qBob : Qubit, qAlice : Qubit) : Bool[] {
|
||||
// Declare a Bool array in which the result will be stored;
|
||||
// the array has to be mutable to allow updating its elements.
|
||||
mutable decoded_bits = new Bool[2];
|
||||
|
||||
// Time to get our state back, by performing transformations as follows.
|
||||
// Notice that it's important to keep the order right. The qubits that are
|
||||
|
@ -83,16 +77,12 @@ namespace Quantum.Kata.SuperdenseCoding {
|
|||
// |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2) ---> |11⟩
|
||||
|
||||
// So we can retrieve the encoded bits just by measuring.
|
||||
set decoded_bits[0] = M(qAlice) == One;
|
||||
set decoded_bits[1] = M(qBob) == One;
|
||||
|
||||
return decoded_bits;
|
||||
return [M(qAlice) == One, M(qBob) == One];
|
||||
}
|
||||
|
||||
|
||||
// Task 4. Superdense coding protocol end-to-end
|
||||
operation SuperdenseCodingProtocol_Reference (message : Bool[]) : Bool[] {
|
||||
mutable decoded_bits = new Bool[2];
|
||||
|
||||
// Get a temporary qubit register for the protocol run.
|
||||
using (qs = Qubit[2]) {
|
||||
|
@ -111,13 +101,12 @@ namespace Quantum.Kata.SuperdenseCoding {
|
|||
// STEP 3:
|
||||
// Bob receives the qubit from Alice and can now
|
||||
// manipulate and measure both qubits to get the encoded data.
|
||||
set decoded_bits = DecodeMessageFromQubits_Reference(qs[1], qs[0]);
|
||||
let decoded_bits = DecodeMessageFromQubits_Reference(qs[1], qs[0]);
|
||||
|
||||
// Make sure that we return qubits back in 0 state.
|
||||
// Make sure that we return qubits back in 0 state before returning the decoded bits.
|
||||
ResetAll(qs);
|
||||
return decoded_bits;
|
||||
}
|
||||
|
||||
return decoded_bits;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
namespace Quantum.Kata.SuperdenseCoding {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
|
||||
|
||||
|
@ -42,7 +43,7 @@ namespace Quantum.Kata.SuperdenseCoding {
|
|||
operation CreateEntangledPair (qs : Qubit[]) : Unit {
|
||||
// The following lines enforce the constraints on the input that you are given.
|
||||
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
EqualityFactI(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ namespace Quantum.Kata.SuperdenseCoding {
|
|||
// The state of the qubits in the end of the operation doesn't matter.
|
||||
operation DecodeMessageFromQubits (qBob : Qubit, qAlice : Qubit) : Bool[] {
|
||||
// Declare a Bool array in which the result will be stored;
|
||||
// the array has to be mutable to allow updating its elements.
|
||||
// the variable has to be mutable to allow updating it.
|
||||
mutable decoded_bits = new Bool[2];
|
||||
|
||||
// ...
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
|
||||
namespace Quantum.Kata.SuperdenseCoding {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation AssertEqualOnZeroState (N : Int, taskImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
operation AssertEqualOnZeroState (N : Int, taskImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit is Adj)) : Unit {
|
||||
using (qs = Qubit[N]) {
|
||||
// apply operation that needs to be tested
|
||||
taskImpl(qs);
|
||||
|
@ -39,18 +39,16 @@ namespace Quantum.Kata.SuperdenseCoding {
|
|||
// Helper operation that runs superdense coding protocol using two building blocks
|
||||
// specified as first two parameters.
|
||||
operation ComposeProtocol (encodeOp : ((Qubit, Bool[]) => Unit), decodeOp : ((Qubit, Qubit) => Bool[]), message : Bool[]) : Bool[] {
|
||||
mutable result = new Bool[2];
|
||||
|
||||
using (qs = Qubit[2]) {
|
||||
CreateEntangledPair_Reference(qs);
|
||||
encodeOp(qs[0], message);
|
||||
set result = decodeOp(qs[1], qs[0]);
|
||||
let result = decodeOp(qs[1], qs[0]);
|
||||
|
||||
// Make sure that we return qubits back in 0 state.
|
||||
ResetAll(qs);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,18 +56,16 @@ namespace Quantum.Kata.SuperdenseCoding {
|
|||
// Helper operation that runs superdense coding protocol (specified by protocolOp)
|
||||
// on all possible input values and verifies that decoding result matches the inputs
|
||||
operation TestProtocol (protocolOp : (Bool[] => Bool[])) : Unit {
|
||||
mutable data = new Bool[2];
|
||||
|
||||
// Loop over the 4 possible combinations of two bits
|
||||
for (n in 0 .. 3) {
|
||||
set data[0] = 1 == n / 2;
|
||||
set data[1] = 1 == n % 2;
|
||||
let data = [1 == n / 2, 1 == n % 2];
|
||||
|
||||
for (iter in 1 .. 100) {
|
||||
let result = protocolOp(data);
|
||||
|
||||
// Now test if the bits were transfered correctly.
|
||||
AssertBoolArrayEqual(result, data, $"The message {data} was transfered incorrectly as {result}");
|
||||
AllEqualityFactB(result, data, $"The message {data} was transfered incorrectly as {result}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,36 +10,31 @@
|
|||
|
||||
namespace Quantum.Kata.Superposition {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Measurement;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// Task 1. Plus state
|
||||
// Input: a qubit in |0⟩ state (stored in an array of length 1).
|
||||
// Goal: create a |+⟩ state on this qubit (|+⟩ = (|0⟩ + |1⟩) / sqrt(2)).
|
||||
operation PlusState_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
H(qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation PlusState_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
H(qs[0]);
|
||||
}
|
||||
|
||||
|
||||
// Task 2. Minus state
|
||||
// Input: a qubit in |0⟩ state (stored in an array of length 1).
|
||||
// Goal: create a |-⟩ state on this qubit (|-⟩ = (|0⟩ - |1⟩) / sqrt(2)).
|
||||
operation MinusState_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
X(qs[0]);
|
||||
H(qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation MinusState_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
X(qs[0]);
|
||||
H(qs[0]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,71 +43,58 @@ namespace Quantum.Kata.Superposition {
|
|||
// 1) a qubit in |0⟩ state (stored in an array of length 1).
|
||||
// 2) angle alpha, in radians, represented as Double
|
||||
// Goal: create a cos(alpha) * |0⟩ + sin(alpha) * |1⟩ state on this qubit.
|
||||
operation UnequalSuperposition_Reference (qs : Qubit[], alpha : Double) : Unit {
|
||||
|
||||
body (...) {
|
||||
// Hint: Experiment with rotation gates from Microsoft.Quantum.Primitive
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation UnequalSuperposition_Reference (qs : Qubit[], alpha : Double) : Unit
|
||||
is Adj {
|
||||
|
||||
// Hint: Experiment with rotation gates from Microsoft.Quantum.Primitive
|
||||
Ry(2.0 * alpha, qs[0]);
|
||||
}
|
||||
|
||||
|
||||
// Task 4. Superposition of all basis vectors on two qubits
|
||||
operation AllBasisVectors_TwoQubits_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
// Since a Hadamard gate will change |0⟩ into |+⟩ = (|0⟩ + |1⟩)/sqrt(2)
|
||||
// And the desired state is just a tensor product |+⟩|+⟩, we can apply
|
||||
// a Hadamard transformation to each qubit.
|
||||
H(qs[0]);
|
||||
H(qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation AllBasisVectors_TwoQubits_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
// Since a Hadamard gate will change |0⟩ into |+⟩ = (|0⟩ + |1⟩)/sqrt(2)
|
||||
// And the desired state is just a tensor product |+⟩|+⟩, we can apply
|
||||
// a Hadamard transformation to each qubit.
|
||||
H(qs[0]);
|
||||
H(qs[1]);
|
||||
}
|
||||
|
||||
|
||||
// Task 5. Superposition of basis vectors with phases
|
||||
operation AllBasisVectorsWithPhases_TwoQubits_Reference (qs : Qubit[]) : Unit {
|
||||
operation AllBasisVectorsWithPhases_TwoQubits_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// Question:
|
||||
// Is this state separable?
|
||||
// Question:
|
||||
// Is this state separable?
|
||||
|
||||
// Answer:
|
||||
// Yes. It is. We can see that:
|
||||
// ((|0⟩ - |1⟩) / sqrt(2)) ⊗ ((|0⟩ + i*|1⟩) / sqrt(2)) is equal to the desired
|
||||
// state, so we can create it by doing operations on each qubit independently.
|
||||
// Answer:
|
||||
// Yes. It is. We can see that:
|
||||
// ((|0⟩ - |1⟩) / sqrt(2)) ⊗ ((|0⟩ + i*|1⟩) / sqrt(2)) is equal to the desired
|
||||
// state, so we can create it by doing operations on each qubit independently.
|
||||
|
||||
// We can see that the first qubit is in state |-⟩ and the second in state |i⟩,
|
||||
// so the transformations that we need are:
|
||||
// We can see that the first qubit is in state |-⟩ and the second in state |i⟩,
|
||||
// so the transformations that we need are:
|
||||
|
||||
// Qubit 0 is taken into |+⟩ and then z-rotated into |-⟩.
|
||||
H(qs[0]);
|
||||
Z(qs[0]);
|
||||
// Qubit 0 is taken into |+⟩ and then z-rotated into |-⟩.
|
||||
H(qs[0]);
|
||||
Z(qs[0]);
|
||||
|
||||
// Qubit 1 is taken into |+⟩ and then z-rotated into |i⟩.
|
||||
H(qs[1]);
|
||||
S(qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
// Qubit 1 is taken into |+⟩ and then z-rotated into |i⟩.
|
||||
H(qs[1]);
|
||||
S(qs[1]);
|
||||
}
|
||||
|
||||
|
||||
// Task 6. Bell state
|
||||
// Input: two qubits in |00⟩ state (stored in an array of length 2).
|
||||
// Goal: create a Bell state |Φ⁺⟩ = (|00⟩ + |11⟩) / sqrt(2) on these qubits.
|
||||
operation BellState_Reference (qs : Qubit[]) : Unit {
|
||||
|
||||
body (...) {
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation BellState_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,40 +107,34 @@ namespace Quantum.Kata.Superposition {
|
|||
// 1: |Φ⁻⟩ = (|00⟩ - |11⟩) / sqrt(2)
|
||||
// 2: |Ψ⁺⟩ = (|01⟩ + |10⟩) / sqrt(2)
|
||||
// 3: |Ψ⁻⟩ = (|01⟩ - |10⟩) / sqrt(2)
|
||||
operation AllBellStates_Reference (qs : Qubit[], index : Int) : Unit {
|
||||
operation AllBellStates_Reference (qs : Qubit[], index : Int) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
H(qs[0]);
|
||||
CNOT(qs[0], qs[1]);
|
||||
|
||||
// now we have |00⟩ + |11⟩ - modify it based on index arg
|
||||
if (index % 2 == 1) {
|
||||
// negative phase
|
||||
Z(qs[1]);
|
||||
}
|
||||
if (index / 2 == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
// now we have |00⟩ + |11⟩ - modify it based on index arg
|
||||
if (index % 2 == 1) {
|
||||
// negative phase
|
||||
Z(qs[1]);
|
||||
}
|
||||
if (index / 2 == 1) {
|
||||
X(qs[1]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
// Task 8. Greenberger–Horne–Zeilinger state
|
||||
// Input: N qubits in |0...0⟩ state.
|
||||
// Goal: create a GHZ state (|0...0⟩ + |1...1⟩) / sqrt(2) on these qubits.
|
||||
operation GHZ_State_Reference (qs : Qubit[]) : Unit {
|
||||
operation GHZ_State_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
H(qs[0]);
|
||||
H(qs[0]);
|
||||
|
||||
for (i in 1 .. Length(qs) - 1) {
|
||||
CNOT(qs[0], qs[i]);
|
||||
}
|
||||
for (q in Rest(qs)) {
|
||||
CNOT(qs[0], q);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,15 +142,12 @@ namespace Quantum.Kata.Superposition {
|
|||
// Input: N qubits in |0...0⟩ state.
|
||||
// Goal: create an equal superposition of all basis vectors from |0...0⟩ to |1...1⟩
|
||||
// (i.e. state (|0...0⟩ + ... + |1...1⟩) / sqrt(2^N) ).
|
||||
operation AllBasisVectorsSuperposition_Reference (qs : Qubit[]) : Unit {
|
||||
operation AllBasisVectorsSuperposition_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
for (i in 0 .. Length(qs) - 1) {
|
||||
H(qs[i]);
|
||||
}
|
||||
for (q in qs) {
|
||||
H(q);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,20 +155,17 @@ namespace Quantum.Kata.Superposition {
|
|||
// Task 10. |00⟩ + |01⟩ + |10⟩ state
|
||||
// Input: 2 qubits in |00⟩ state.
|
||||
// Goal: create the state (|00⟩ + |01⟩ + |10⟩) / sqrt(3) on these qubits.
|
||||
operation ThreeStates_TwoQubits_Reference (qs : Qubit[]) : Unit {
|
||||
operation ThreeStates_TwoQubits_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// Follow Niel's answer at https://quantumcomputing.stackexchange.com/a/2313/
|
||||
// Follow Niel's answer at https://quantumcomputing.stackexchange.com/a/2313/
|
||||
|
||||
// Rotate first qubit to (sqrt(2) |0⟩ + |1⟩) / sqrt(3) (task 1.4 from BasicGates kata)
|
||||
let theta = ArcSin(1.0 / Sqrt(3.0));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
// Rotate first qubit to (sqrt(2) |0⟩ + |1⟩) / sqrt(3) (task 1.4 from BasicGates kata)
|
||||
let theta = ArcSin(1.0 / Sqrt(3.0));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
|
||||
// Split the state sqrt(2) |0⟩ ⊗ |0⟩ into |00⟩ + |01⟩
|
||||
(ControlledOnInt(0, H))([qs[0]], qs[1]);
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
// Split the state sqrt(2) |0⟩ ⊗ |0⟩ into |00⟩ + |01⟩
|
||||
(ControlledOnInt(0, H))([qs[0]], qs[1]);
|
||||
}
|
||||
|
||||
// Alternative solution, based on post-selection
|
||||
|
@ -226,24 +196,21 @@ namespace Quantum.Kata.Superposition {
|
|||
// You are guaranteed that the qubit array and the bit string have the same length.
|
||||
// You are guaranteed that the first bit of the bit string is true.
|
||||
// Example: for bit string = [true, false] the qubit state required is (|00⟩ + |10⟩) / sqrt(2).
|
||||
operation ZeroAndBitstringSuperposition_Reference (qs : Qubit[], bits : Bool[]) : Unit {
|
||||
operation ZeroAndBitstringSuperposition_Reference (qs : Qubit[], bits : Bool[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
AssertIntEqual(Length(bits), Length(qs), "Arrays should have the same length");
|
||||
AssertBoolEqual(bits[0], true, "First bit of the input bit string should be set to true");
|
||||
EqualityFactI(Length(bits), Length(qs), "Arrays should have the same length");
|
||||
EqualityFactB(bits[0], true, "First bit of the input bit string should be set to true");
|
||||
|
||||
// Hadamard first qubit
|
||||
H(qs[0]);
|
||||
// Hadamard first qubit
|
||||
H(qs[0]);
|
||||
|
||||
// iterate through the bit string and CNOT to qubits corresponding to true bits
|
||||
for (i in 1 .. Length(qs) - 1) {
|
||||
if (bits[i]) {
|
||||
CNOT(qs[0], qs[i]);
|
||||
}
|
||||
// iterate through the bit string and CNOT to qubits corresponding to true bits
|
||||
for (i in 1 .. Length(qs) - 1) {
|
||||
if (bits[i]) {
|
||||
CNOT(qs[0], qs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -270,35 +237,32 @@ namespace Quantum.Kata.Superposition {
|
|||
}
|
||||
|
||||
|
||||
operation TwoBitstringSuperposition_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Unit {
|
||||
operation TwoBitstringSuperposition_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
// find the index of the first bit at which the bit strings are different
|
||||
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
|
||||
// find the index of the first bit at which the bit strings are different
|
||||
let firstDiff = FindFirstDiff_Reference(bits1, bits2);
|
||||
|
||||
// Hadamard corresponding qubit to create superposition
|
||||
H(qs[firstDiff]);
|
||||
// Hadamard corresponding qubit to create superposition
|
||||
H(qs[firstDiff]);
|
||||
|
||||
// iterate through the bit strings again setting the final state of qubits
|
||||
for (i in 0 .. Length(qs) - 1) {
|
||||
if (bits1[i] == bits2[i]) {
|
||||
// if two bits are the same apply X or nothing
|
||||
if (bits1[i]) {
|
||||
// iterate through the bit strings again setting the final state of qubits
|
||||
for (i in 0 .. Length(qs) - 1) {
|
||||
if (bits1[i] == bits2[i]) {
|
||||
// if two bits are the same apply X or nothing
|
||||
if (bits1[i]) {
|
||||
X(qs[i]);
|
||||
}
|
||||
} else {
|
||||
// if two bits are different, set their difference using CNOT
|
||||
if (i > firstDiff) {
|
||||
CNOT(qs[firstDiff], qs[i]);
|
||||
if (bits1[i] != bits1[firstDiff]) {
|
||||
X(qs[i]);
|
||||
}
|
||||
} else {
|
||||
// if two bits are different, set their difference using CNOT
|
||||
if (i > firstDiff) {
|
||||
CNOT(qs[firstDiff], qs[i]);
|
||||
if (bits1[i] != bits1[firstDiff]) {
|
||||
X(qs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -312,36 +276,33 @@ namespace Quantum.Kata.Superposition {
|
|||
// bit values false and true correspond to |0⟩ and |1⟩ states.
|
||||
//
|
||||
// Goal: create an equal superposition of the four basis states given by the bit strings.
|
||||
operation FourBitstringSuperposition_Reference (qs : Qubit[], bits : Bool[][]) : Unit {
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
operation FourBitstringSuperposition_Reference (qs : Qubit[], bits : Bool[][]) : Unit
|
||||
is Adj {
|
||||
let N = Length(qs);
|
||||
|
||||
using (anc = Qubit[2]) {
|
||||
// Put two ancillas into equal superposition of 2-qubit basis states
|
||||
ApplyToEachA(H, anc);
|
||||
using (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 .. N - 1) {
|
||||
if ((bits[i])[j]) {
|
||||
(ControlledOnInt(i, X))(anc, qs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Uncompute the ancillas, using patterns on main qubits as control
|
||||
for (i in 0 .. 3) {
|
||||
if (i % 2 == 1) {
|
||||
(ControlledOnBitString(bits[i], X))(qs, anc[0]);
|
||||
}
|
||||
if (i / 2 == 1) {
|
||||
(ControlledOnBitString(bits[i], X))(qs, anc[1]);
|
||||
// Set up the right pattern on the main qubits with control on ancillas
|
||||
for (i in 0 .. 3) {
|
||||
for (j in 0 .. N - 1) {
|
||||
if ((bits[i])[j]) {
|
||||
(ControlledOnInt(i, X))(anc, qs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Uncompute the ancillas, using patterns on main qubits as control
|
||||
for (i in 0 .. 3) {
|
||||
if (i % 2 == 1) {
|
||||
(ControlledOnBitString(bits[i], X))(qs, anc[0]);
|
||||
}
|
||||
if (i / 2 == 1) {
|
||||
(ControlledOnBitString(bits[i], X))(qs, anc[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
|
@ -351,36 +312,33 @@ namespace Quantum.Kata.Superposition {
|
|||
// Goal: create a W state (https://en.wikipedia.org/wiki/W_state) on these qubits.
|
||||
// W state is an equal superposition of all basis states on N qubits of Hamming weight 1.
|
||||
// Example: for N = 4, W state is (|1000⟩ + |0100⟩ + |0010⟩ + |0001⟩) / 2.
|
||||
operation WState_PowerOfTwo_Reference (qs : Qubit[]) : Unit {
|
||||
operation WState_PowerOfTwo_Reference (qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
let N = Length(qs);
|
||||
|
||||
if (N == 1) {
|
||||
// base of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
} else {
|
||||
let K = N / 2;
|
||||
if (N == 1) {
|
||||
// base of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
} else {
|
||||
let K = N / 2;
|
||||
|
||||
// create W state on the first K qubits
|
||||
WState_PowerOfTwo_Reference(qs[0 .. K - 1]);
|
||||
// create W state on the first K qubits
|
||||
WState_PowerOfTwo_Reference(qs[0 .. K - 1]);
|
||||
|
||||
// the next K qubits are in |0...0⟩ state
|
||||
// allocate ancilla in |+⟩ state
|
||||
using (anc = Qubit[1]) {
|
||||
H(anc[0]);
|
||||
// the next K qubits are in |0...0⟩ state
|
||||
// allocate ancilla in |+⟩ state
|
||||
using (anc = Qubit()) {
|
||||
H(anc);
|
||||
|
||||
for (i in 0 .. K - 1) {
|
||||
Controlled SWAP(anc, (qs[i], qs[i + K]));
|
||||
}
|
||||
for (i in K .. N - 1) {
|
||||
CNOT(qs[i], anc[0]);
|
||||
}
|
||||
for (i in 0 .. K - 1) {
|
||||
Controlled SWAP([anc], (qs[i], qs[i + K]));
|
||||
}
|
||||
for (i in K .. N - 1) {
|
||||
CNOT(qs[i], anc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
}
|
||||
|
||||
|
||||
|
@ -392,31 +350,26 @@ namespace Quantum.Kata.Superposition {
|
|||
// Example: for N = 3, W state is (|100⟩ + |010⟩ + |001⟩) / sqrt(3).
|
||||
|
||||
// general solution based on rotations and recursive application of controlled generation routine
|
||||
operation WState_Arbitrary_Reference (qs : Qubit[]) : Unit {
|
||||
operation WState_Arbitrary_Reference (qs : Qubit[]) : Unit
|
||||
is Adj + Ctl {
|
||||
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
let N = Length(qs);
|
||||
|
||||
if (N == 1) {
|
||||
// base case of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
} else {
|
||||
// |W_N⟩ = |0⟩|W_(N-1)⟩ + |1⟩|0...0⟩
|
||||
// do a rotation on the first qubit to split it into |0⟩ and |1⟩ with proper weights
|
||||
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
|
||||
let theta = ArcSin(1.0 / Sqrt(ToDouble(N)));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
if (N == 1) {
|
||||
// base case of recursion: |1⟩
|
||||
X(qs[0]);
|
||||
} else {
|
||||
// |W_N⟩ = |0⟩|W_(N-1)⟩ + |1⟩|0...0⟩
|
||||
// do a rotation on the first qubit to split it into |0⟩ and |1⟩ with proper weights
|
||||
// |0⟩ -> sqrt((N-1)/N) |0⟩ + 1/sqrt(N) |1⟩
|
||||
let theta = ArcSin(1.0 / Sqrt(IntAsDouble(N)));
|
||||
Ry(2.0 * theta, qs[0]);
|
||||
|
||||
// do a zero-controlled W-state generation for qubits 1..N-1
|
||||
X(qs[0]);
|
||||
Controlled WState_Arbitrary_Reference(qs[0 .. 0], qs[1 .. N - 1]);
|
||||
X(qs[0]);
|
||||
}
|
||||
// do a zero-controlled W-state generation for qubits 1..N-1
|
||||
X(qs[0]);
|
||||
Controlled WState_Arbitrary_Reference(qs[0 .. 0], qs[1 .. N - 1]);
|
||||
X(qs[0]);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
controlled distribute;
|
||||
controlled adjoint distribute;
|
||||
}
|
||||
|
||||
|
||||
|
@ -432,21 +385,18 @@ namespace Quantum.Kata.Superposition {
|
|||
|
||||
// Given a qubit in |0⟩ state and a denominator N,
|
||||
// transform the qubit to state sqrt((N-1) / N) |0⟩ + sqrt(1/N) |1⟩.
|
||||
operation FractionSuperposition(denominator : Int, q : Qubit) : Unit {
|
||||
body (...) {
|
||||
if (denominator == 1) {
|
||||
X(q);
|
||||
} else {
|
||||
// represent the target state as cos(theta) * |0⟩ + sin(theta) * |1⟩, as in task 1.3
|
||||
let denom = ToDouble(denominator);
|
||||
let num = denom - 1.0;
|
||||
let theta = ArcCos(Sqrt(num / denom));
|
||||
Ry(2.0 * theta, q);
|
||||
}
|
||||
operation FractionSuperposition(denominator : Int, q : Qubit) : Unit
|
||||
is Adj + Ctl {
|
||||
|
||||
if (denominator == 1) {
|
||||
X(q);
|
||||
} else {
|
||||
// represent the target state as cos(theta) * |0⟩ + sin(theta) * |1⟩, as in task 1.3
|
||||
let denom = IntAsDouble(denominator);
|
||||
let num = denom - 1.0;
|
||||
let theta = ArcCos(Sqrt(num / denom));
|
||||
Ry(2.0 * theta, q);
|
||||
}
|
||||
adjoint invert;
|
||||
controlled distribute;
|
||||
controlled adjoint distribute;
|
||||
}
|
||||
|
||||
|
||||
|
@ -463,7 +413,7 @@ namespace Quantum.Kata.Superposition {
|
|||
mutable P = 1;
|
||||
for (i in 1 .. 6) {
|
||||
if (P < N) {
|
||||
set P = P * 2;
|
||||
set P *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%package Microsoft.Quantum.Katas::0.5.1904.1302"
|
||||
"%package Microsoft.Quantum.Katas::0.6.1905.301"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -43,13 +43,13 @@
|
|||
"> The package versions in the output of the cell above should always match. If you are running the Notebooks locally and the versions do not match, please install the IQ# version that matches the version of the `Microsoft.Quantum.Katas` package.\n",
|
||||
"> <details>\n",
|
||||
"> <summary><u>How to install the right IQ# version</u></summary>\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.5.1904.1302, the installation steps are as follows:\n",
|
||||
"> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.6.1905.301, the installation steps are as follows:\n",
|
||||
">\n",
|
||||
"> 1. Stop the kernel.\n",
|
||||
"> 2. Uninstall the existing version of IQ#:\n",
|
||||
"> dotnet tool uninstall microsoft.quantum.iqsharp -g\n",
|
||||
"> 3. Install the matching version:\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.5.1904.1302\n",
|
||||
"> dotnet tool install microsoft.quantum.iqsharp -g --version 0.6.1905.301\n",
|
||||
"> 4. Reinstall the kernel:\n",
|
||||
"> dotnet iqsharp install\n",
|
||||
"> 5. Restart the Notebook.\n",
|
||||
|
@ -125,7 +125,7 @@
|
|||
"<br/>\n",
|
||||
"<details>\n",
|
||||
" <summary>Need a hint? Click here</summary>\n",
|
||||
" Experiment with rotation gates from Microsoft.Quantum.Primitive namespace.\n",
|
||||
" Experiment with rotation gates from Microsoft.Quantum.Intrinsic namespace.\n",
|
||||
" Note that all rotation operators rotate the state by <i>half</i> of its angle argument.\n",
|
||||
"</details>"
|
||||
]
|
||||
|
@ -321,7 +321,7 @@
|
|||
"<br/>\n",
|
||||
"<details>\n",
|
||||
" <summary>Need a hint? Click here</summary>\n",
|
||||
" If you need trigonometric functions, you can find them in Microsoft.Quantum.Extensions.Math namespace; you'll need to add <pre>open Microsoft.Quantum.Extensions.Math;</pre> to the code before the operation definition.\n",
|
||||
" If you need trigonometric functions, you can find them in Microsoft.Quantum.Math namespace; you'll need to add <pre>open Microsoft.Quantum.Math;</pre> to the code before the operation definition.\n",
|
||||
"</details>"
|
||||
]
|
||||
},
|
||||
|
@ -480,7 +480,7 @@
|
|||
"<br/>\n",
|
||||
"<details>\n",
|
||||
" <summary>Need a hint? Click here</summary>\n",
|
||||
" You can modify the signature of the given operation to specify its controlled variant.\n",
|
||||
" You can modify the signature of the given operation to specify its controlled specialization.\n",
|
||||
"</details>"
|
||||
]
|
||||
},
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
|
||||
namespace Quantum.Kata.Superposition {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Welcome!
|
||||
|
@ -69,7 +70,7 @@ namespace Quantum.Kata.Superposition {
|
|||
operation AllBasisVectors_TwoQubits (qs : Qubit[]) : Unit {
|
||||
// The following lines enforce the constraints on the input that you are given.
|
||||
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
EqualityFactI(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
@ -81,7 +82,7 @@ namespace Quantum.Kata.Superposition {
|
|||
operation AllBasisVectorsWithPhases_TwoQubits (qs : Qubit[]) : Unit {
|
||||
// The following lines enforce the constraints on the input that you are given.
|
||||
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
EqualityFactI(Length(qs), 2, "The array should have exactly 2 qubits.");
|
||||
|
||||
// Hint: Is this state separable?
|
||||
// ...
|
||||
|
@ -149,8 +150,8 @@ namespace Quantum.Kata.Superposition {
|
|||
operation ZeroAndBitstringSuperposition (qs : Qubit[], bits : Bool[]) : Unit {
|
||||
// The following lines enforce the constraints on the input that you are given.
|
||||
// You don't need to modify them. Feel free to remove them, this won't cause your code to fail.
|
||||
AssertIntEqual(Length(bits), Length(qs), "Arrays should have the same length");
|
||||
AssertBoolEqual(bits[0], true, "First bit of the input bit string should be set to true");
|
||||
EqualityFactI(Length(bits), Length(qs), "Arrays should have the same length");
|
||||
EqualityFactB(bits[0], true, "First bit of the input bit string should be set to true");
|
||||
|
||||
// ...
|
||||
}
|
||||
|
|
|
@ -9,15 +9,15 @@
|
|||
|
||||
namespace Quantum.Kata.Superposition {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation AssertEqualOnZeroState (N : Int, testImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit : Adjoint)) : Unit {
|
||||
operation AssertEqualOnZeroState (N : Int, testImpl : (Qubit[] => Unit), refImpl : (Qubit[] => Unit is Adj)) : Unit {
|
||||
using (qs = Qubit[N]) {
|
||||
// apply operation that needs to be tested
|
||||
testImpl(qs);
|
||||
|
@ -53,7 +53,7 @@ namespace Quantum.Kata.Superposition {
|
|||
AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.75 * PI()), MinusState_Reference);
|
||||
|
||||
for (i in 1 .. 36) {
|
||||
let alpha = ((2.0 * PI()) * ToDouble(i)) / 36.0;
|
||||
let alpha = ((2.0 * PI()) * IntAsDouble(i)) / 36.0;
|
||||
AssertEqualOnZeroState(1, UnequalSuperposition(_, alpha), UnequalSuperposition_Reference(_, alpha));
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ namespace Quantum.Kata.Superposition {
|
|||
repeat {
|
||||
mutable ok = true;
|
||||
for (i in 0 .. 3) {
|
||||
set numbers[i] = RandomInt(1 <<< N);
|
||||
set numbers w/= i <- RandomInt(1 <<< N);
|
||||
for (j in 0 .. i - 1) {
|
||||
if (numbers[i] == numbers[j]) {
|
||||
set ok = false;
|
||||
|
@ -195,7 +195,7 @@ namespace Quantum.Kata.Superposition {
|
|||
|
||||
// convert numbers to bit strings
|
||||
for (i in 0 .. 3) {
|
||||
set bits[i] = BoolArrFromPositiveInt(numbers[i], N);
|
||||
set bits w/= i <- IntAsBoolArray(numbers[i], N);
|
||||
}
|
||||
|
||||
AssertEqualOnZeroState(N, FourBitstringSuperposition(_, bits), FourBitstringSuperposition_Reference(_, bits));
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
|
||||
namespace Quantum.Kata.Teleportation {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Preparation;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
@ -20,14 +21,10 @@ namespace Quantum.Kata.Teleportation {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. Entangled pair
|
||||
operation Entangle_Reference (qAlice : Qubit, qBob : Qubit) : Unit {
|
||||
|
||||
body (...) {
|
||||
H(qAlice);
|
||||
CNOT(qAlice, qBob);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
operation Entangle_Reference (qAlice : Qubit, qBob : Qubit) : Unit
|
||||
is Adj {
|
||||
H(qAlice);
|
||||
CNOT(qAlice, qBob);
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,17 +60,16 @@ namespace Quantum.Kata.Teleportation {
|
|||
|
||||
// Task 1.5. Prepare the message specified and send it (Alice's task)
|
||||
operation PrepareAndSendMessage_Reference (qAlice : Qubit, basis : Pauli, state : Bool) : (Bool, Bool) {
|
||||
mutable classicalBits = (false, false);
|
||||
using (qs = Qubit[1]) {
|
||||
if (state) {
|
||||
X(qs[0]);
|
||||
}
|
||||
|
||||
PrepareQubit(basis, qs[0]);
|
||||
set classicalBits = SendMessage_Reference(qAlice, qs[0]);
|
||||
let classicalBits = SendMessage_Reference(qAlice, qs[0]);
|
||||
Reset(qs[0]);
|
||||
return classicalBits;
|
||||
}
|
||||
return classicalBits;
|
||||
}
|
||||
|
||||
|
||||
|
@ -151,25 +147,22 @@ namespace Quantum.Kata.Teleportation {
|
|||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 4.1. Entangled trio
|
||||
operation EntangleThreeQubits_Reference (qAlice : Qubit, qBob : Qubit, qCharlie : Qubit) : Unit {
|
||||
operation EntangleThreeQubits_Reference (qAlice : Qubit, qBob : Qubit, qCharlie : Qubit) : Unit
|
||||
is Adj {
|
||||
|
||||
body (...) {
|
||||
H(qAlice);
|
||||
H(qBob);
|
||||
X(qCharlie);
|
||||
H(qAlice);
|
||||
H(qBob);
|
||||
X(qCharlie);
|
||||
|
||||
CCNOT(qAlice, qBob, qCharlie);
|
||||
CCNOT(qAlice, qBob, qCharlie);
|
||||
|
||||
X(qAlice);
|
||||
X(qBob);
|
||||
X(qAlice);
|
||||
X(qBob);
|
||||
|
||||
CCNOT(qAlice, qBob, qCharlie);
|
||||
CCNOT(qAlice, qBob, qCharlie);
|
||||
|
||||
X(qAlice);
|
||||
X(qBob);
|
||||
}
|
||||
|
||||
adjoint invert;
|
||||
X(qAlice);
|
||||
X(qBob);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
namespace Quantum.Kata.Teleportation {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
namespace Quantum.Kata.Teleportation {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
@ -79,7 +79,7 @@ namespace Quantum.Kata.Teleportation {
|
|||
// which makes testing easier.
|
||||
operation TeleportTestHelper (
|
||||
teleportOp : ((Qubit, Qubit, Qubit) => Unit),
|
||||
setupPsiOp : (Qubit => Unit : Adjoint)) : Unit {
|
||||
setupPsiOp : (Qubit => Unit is Adj)) : Unit {
|
||||
|
||||
using (qs = Qubit[3]) {
|
||||
let qMessage = qs[0];
|
||||
|
@ -169,7 +169,7 @@ namespace Quantum.Kata.Teleportation {
|
|||
StatePrep_BellState(qAlice, qBob, 0);
|
||||
let classicalBits = prepareAndSendMessageOp(qAlice, basis, sentState);
|
||||
let receivedState = reconstructAndMeasureMessageOp(qBob, classicalBits, basis);
|
||||
AssertBoolEqual(receivedState, sentState, $"Sent and received states were not equal for {sentState} eigenstate in {basis} basis.");
|
||||
EqualityFactB(receivedState, sentState, $"Sent and received states were not equal for {sentState} eigenstate in {basis} basis.");
|
||||
ResetAll([qAlice, qBob]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace Quantum.Kata.UnitaryPatterns
|
|||
return base.Apply();
|
||||
}
|
||||
|
||||
public override QArray<Qubit> Apply(long count)
|
||||
public override IQArray<Qubit> Apply(long count)
|
||||
{
|
||||
_sim._qubitsAllocated += count;
|
||||
if (_sim._qubitsAllocated > _sim._maxQubitsAllocated)
|
||||
|
@ -137,7 +137,7 @@ namespace Quantum.Kata.UnitaryPatterns
|
|||
base.Apply(q);
|
||||
}
|
||||
|
||||
public override void Apply(QArray<Qubit> qubits)
|
||||
public override void Apply(IQArray<Qubit> qubits)
|
||||
{
|
||||
_sim._qubitsAllocated -= qubits.Length;
|
||||
base.Apply(qubits);
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
|
||||
namespace Quantum.Kata.UnitaryPatterns {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// Task 1. Main diagonal
|
||||
|
@ -78,20 +79,17 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
|
||||
|
||||
// Task 10. Increasing blocks
|
||||
operation IncreasingBlocks_Reference (qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
let N = Length(qs);
|
||||
// for N = 1, we need an identity
|
||||
if (N > 1) {
|
||||
// do the bottom-right quarter
|
||||
ApplyToEachCA(Controlled H([Tail(qs)], _), Most(qs));
|
||||
// do the top-left quarter by calling the same operation recursively
|
||||
(ControlledOnInt(0, IncreasingBlocks_Reference))([Tail(qs)], Most(qs));
|
||||
}
|
||||
operation IncreasingBlocks_Reference (qs : Qubit[]) : Unit
|
||||
is Adj + Ctl {
|
||||
|
||||
let N = Length(qs);
|
||||
// for N = 1, we need an identity
|
||||
if (N > 1) {
|
||||
// do the bottom-right quarter
|
||||
ApplyToEachCA(Controlled H([Tail(qs)], _), Most(qs));
|
||||
// do the top-left quarter by calling the same operation recursively
|
||||
(ControlledOnInt(0, IncreasingBlocks_Reference))([Tail(qs)], Most(qs));
|
||||
}
|
||||
adjoint auto;
|
||||
controlled auto;
|
||||
controlled adjoint auto;
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,27 +114,25 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
operation Decrement (qs : Qubit[]) : Unit {
|
||||
X(qs[0]);
|
||||
for (i in 1..Length(qs)-1) {
|
||||
(Controlled X)(qs[0..i-1], qs[i]);
|
||||
Controlled X(qs[0..i-1], qs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper operation: antidiagonal
|
||||
operation Reflect (qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
ApplyToEachC(X, qs);
|
||||
}
|
||||
controlled auto;
|
||||
operation Reflect (qs : Qubit[]) : Unit
|
||||
is Ctl {
|
||||
ApplyToEachC(X, qs);
|
||||
}
|
||||
|
||||
// Main operation for Task 13
|
||||
operation TIE_Fighter_Reference (qs : Qubit[]) : Unit {
|
||||
let n = Length(qs);
|
||||
X(qs[n-1]);
|
||||
(Controlled Reflect)([qs[n-1]], qs[0..(n-2)]);
|
||||
Controlled Reflect([qs[n-1]], qs[0..(n-2)]);
|
||||
X(qs[n-1]);
|
||||
Decrement(qs[0..(n-2)]);
|
||||
H(qs[n-1]);
|
||||
(Controlled Reflect)([qs[n-1]], qs[0..(n-2)]);
|
||||
Controlled Reflect([qs[n-1]], qs[0..(n-2)]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -152,7 +148,7 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
CNOT(qs[2], qs[0]);
|
||||
CCNOT(qs[0], qs[2], qs[1]);
|
||||
X(qs[2]);
|
||||
(Controlled H)([qs[2]], qs[1]);
|
||||
Controlled H([qs[2]], qs[1]);
|
||||
X(qs[2]);
|
||||
H(qs[0]);
|
||||
CNOT(qs[1], qs[2]);
|
||||
|
@ -173,64 +169,63 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
|
||||
// Helper function for Embed_2x2_Operator: performs a Clifford to implement a base change
|
||||
// that maps basis states index1 to 111...10 and index2 to 111...11 (in big endian notation, i.e., LSB in qs[n-1])
|
||||
operation Embedding_Perm (index1 : Int, index2 : Int, qs : Qubit[]) : Unit {
|
||||
body (...) {
|
||||
let n = Length(qs);
|
||||
let bits1 = BoolArrFromPositiveInt(index1, n);
|
||||
let bits2 = BoolArrFromPositiveInt(index2, n);
|
||||
// find the index of the first bit at which the bit strings are different
|
||||
let diff = FirstDiff(bits1, bits2);
|
||||
operation Embedding_Perm (index1 : Int, index2 : Int, qs : Qubit[]) : Unit
|
||||
is Adj {
|
||||
|
||||
// we care only about 2 inputs: basis state of bits1 and bits2
|
||||
let n = Length(qs);
|
||||
let bits1 = BoolArrFromPositiveInt(index1, n);
|
||||
let bits2 = BoolArrFromPositiveInt(index2, n);
|
||||
// find the index of the first bit at which the bit strings are different
|
||||
let diff = FirstDiff(bits1, bits2);
|
||||
|
||||
// make sure that the state corresponding to bits1 has qs[diff] set to |0⟩
|
||||
if (bits1[diff]) {
|
||||
X(qs[diff]);
|
||||
}
|
||||
// we care only about 2 inputs: basis state of bits1 and bits2
|
||||
|
||||
// make sure that the state corresponding to bits1 has qs[diff] set to |0⟩
|
||||
if (bits1[diff]) {
|
||||
X(qs[diff]);
|
||||
}
|
||||
|
||||
// iterate through the bit strings again, setting the final state of qubits
|
||||
for (i in 0..n-1) {
|
||||
if (bits1[i] == bits2[i]) {
|
||||
// if two bits are the same, set both to 1 using X or nothing
|
||||
// iterate through the bit strings again, setting the final state of qubits
|
||||
for (i in 0..n-1) {
|
||||
if (bits1[i] == bits2[i]) {
|
||||
// if two bits are the same, set both to 1 using X or nothing
|
||||
if (not bits1[i]) {
|
||||
X(qs[i]);
|
||||
}
|
||||
} else {
|
||||
// if two bits are different, set both to 1 using CNOT
|
||||
if (i > diff) {
|
||||
if (not bits1[i]) {
|
||||
X(qs[i]);
|
||||
X(qs[diff]);
|
||||
CNOT(qs[diff], qs[i]);
|
||||
X(qs[diff]);
|
||||
}
|
||||
} else {
|
||||
// if two bits are different, set both to 1 using CNOT
|
||||
if (i > diff) {
|
||||
if (not bits1[i]) {
|
||||
X(qs[diff]);
|
||||
CNOT(qs[diff], qs[i]);
|
||||
X(qs[diff]);
|
||||
}
|
||||
if (not bits2[i]) {
|
||||
CNOT(qs[diff], qs[i]);
|
||||
}
|
||||
if (not bits2[i]) {
|
||||
CNOT(qs[diff], qs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move the differing bit to the last qubit
|
||||
if (diff < n-1) {
|
||||
SWAP(qs[n-1], qs[diff]);
|
||||
}
|
||||
}
|
||||
adjoint auto;
|
||||
|
||||
// move the differing bit to the last qubit
|
||||
if (diff < n-1) {
|
||||
SWAP(qs[n-1], qs[diff]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Helper function: apply the 2x2 unitary operator at the sub-matrix given by indices for 2 rows/columns
|
||||
operation Embed_2x2_Operator (U : (Qubit => Unit : Controlled), index1 : Int, index2 : Int, qs : Qubit[]) : Unit {
|
||||
operation Embed_2x2_Operator (U : (Qubit => Unit is Ctl), index1 : Int, index2 : Int, qs : Qubit[]) : Unit {
|
||||
Embedding_Perm(index1, index2, qs);
|
||||
(Controlled U)(Most(qs), Tail(qs));
|
||||
(Adjoint Embedding_Perm)(index1, index2, qs);
|
||||
Controlled U(Most(qs), Tail(qs));
|
||||
Adjoint Embedding_Perm(index1, index2, qs);
|
||||
}
|
||||
|
||||
|
||||
// Putting everything together: the target pattern is produced by a sequence of controlled H gates.
|
||||
operation Hessenberg_Matrix_Reference (qs : Qubit[]) : Unit {
|
||||
let n = Length(qs);
|
||||
for (i in 2^n-2..-1..0) {
|
||||
for (i in 2^n-2..-1..0) {
|
||||
Embed_2x2_Operator(H, i, i+1, qs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
namespace Quantum.Kata.UnitaryPatterns {
|
||||
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Welcome!
|
||||
|
@ -288,7 +289,7 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
// ..X..X..
|
||||
// XX....XX
|
||||
// XX....XX
|
||||
operation Creeper (qs : Qubit[]) : Unit {
|
||||
operation Creeper (qs : Qubit[]) : Unit {
|
||||
// ...
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
|
||||
namespace Quantum.Kata.UnitaryPatterns {
|
||||
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Arithmetic;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Convert;
|
||||
open Microsoft.Quantum.Extensions.Math;
|
||||
open Microsoft.Quantum.Extensions.Testing;
|
||||
open Microsoft.Quantum.Extensions.Diagnostics;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
@ -45,20 +45,16 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
op(qs);
|
||||
|
||||
// Make sure the solution didn't use any measurements
|
||||
AssertIntEqual(GetOracleCallsCount(M), 0, "You are not allowed to use measurements in this task");
|
||||
AssertIntEqual(GetOracleCallsCount(Measure), 0, "You are not allowed to use measurements in this task");
|
||||
EqualityFactI(GetOracleCallsCount(M), 0, "You are not allowed to use measurements in this task");
|
||||
EqualityFactI(GetOracleCallsCount(Measure), 0, "You are not allowed to use measurements in this task");
|
||||
|
||||
// Test that the result matches the k-th column
|
||||
// DumpMachine($"C:/Tmp/dump{N}_{k}.txt");
|
||||
for (j in 0 .. size - 1) {
|
||||
let nonZero = pattern(size, j, k);
|
||||
|
||||
if (nonZero) {
|
||||
AssertProbInt(j, 0.5 + ε, LittleEndian(qs), 0.5);
|
||||
}
|
||||
else {
|
||||
AssertProbInt(j, 0.0, LittleEndian(qs), ε);
|
||||
}
|
||||
let (expected, tol) = nonZero ? (0.5 + ε, 0.5) | (0.0, ε);
|
||||
AssertProbInt(j, expected, LittleEndian(qs), tol);
|
||||
}
|
||||
|
||||
ResetAll(qs);
|
||||
|
@ -285,10 +281,7 @@ namespace Quantum.Kata.UnitaryPatterns {
|
|||
[ false, false, true, false, false, true, false, false],
|
||||
[ true, true, false, false, false, false, true, true],
|
||||
[ true, true, false, false, false, false, true, true] ];
|
||||
if (size != 8) {
|
||||
return false;
|
||||
}
|
||||
return A[row][col];
|
||||
return size != 8 ? false | A[row][col];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@ -7,9 +7,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# Script to validate Jupyter notebooks.
|
||||
|
||||
#
|
||||
# This function takes a folder with Katas. Copies the corresponding
|
||||
# jupyter notebook into a "Check.ipynb" that replaces the %kata magic
|
||||
# with a %check_kata magic that runs the kata not with the user-supplied code
|
||||
# but with the Reference implementation.
|
||||
# If the execution fails or has warnings, the execution of the notebook
|
||||
# will fail.
|
||||
function validate {
|
||||
Param($folder)
|
||||
pushd $folder
|
||||
|
||||
# Name of the notebook that will be used for checking katas.
|
||||
$CheckNotebook = 'Check.ipynb'
|
||||
|
||||
# Make sure old versions are removed.
|
||||
if (Test-Path $CheckNotebook) {
|
||||
Remove-Item $CheckNotebook
|
||||
}
|
||||
|
||||
# Find the name of the kata's notebook.
|
||||
$Notebook = (Get-ChildItem *.ipynb)
|
||||
Write-Host "Checking notebook $Notebook."
|
||||
|
||||
# convert %kata to %check_kata. run Jupyter nbconvert to execute the kata.
|
||||
(Get-Content $Notebook -Raw) | ForEach-Object { $_.replace('%kata', '%check_kata') } | Set-Content $CheckNotebook -NoNewline
|
||||
jupyter nbconvert $CheckNotebook --execute --ExecutePreprocessor.timeout=120
|
||||
|
||||
# if jupyter returns an error code, return that this notebook is invalid:
|
||||
$invalid = ($LastExitCode -ne 0)
|
||||
Write-Host "Result: " $LastExitCode
|
||||
|
||||
popd
|
||||
return $invalid
|
||||
}
|
||||
|
||||
# List of Katas to verify:
|
||||
$errors = $false
|
||||
$errors = (validate ..\Measurements) -or $errors
|
||||
$errors = (validate ..\BasicGates) -or $errors
|
||||
$errors = (validate ..\Superposition) -or $errors
|
||||
$errors = (validate ..\DeutschJozsaAlgorithm) -or $errors
|
||||
|
||||
$result = 0
|
||||
if ($errors) {
|
||||
Write-Host "##vso[task.logissue type=error;]Validation errors for Jupyter notebooks."
|
||||
$result = 1
|
||||
}
|
||||
|
||||
exit($result)
|
|
@ -7,7 +7,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -119,7 +119,7 @@ namespace Microsoft.Quantum.Katas
|
|||
return base.Apply();
|
||||
}
|
||||
|
||||
public override QArray<Qubit> Apply(long count)
|
||||
public override IQArray<Qubit> Apply(long count)
|
||||
{
|
||||
_sim._qubitsAllocated += count;
|
||||
if (_sim._qubitsAllocated > _sim._maxQubitsAllocated)
|
||||
|
@ -148,7 +148,7 @@ namespace Microsoft.Quantum.Katas
|
|||
base.Apply(q);
|
||||
}
|
||||
|
||||
public override void Apply(QArray<Qubit> qubits)
|
||||
public override void Apply(IQArray<Qubit> qubits)
|
||||
{
|
||||
_sim._qubitsAllocated -= qubits.Length;
|
||||
base.Apply(qubits);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
|
@ -9,7 +9,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Canon" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.6.1905.301" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.6.1905.301" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
namespace Quantum.DumpUnitary
|
||||
{
|
||||
open Microsoft.Quantum.Primitive;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Extensions.Diagnostics;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
|
||||
|
||||
operation DumpUnitaryToFiles (N : Int, unitary : (Qubit[] => Unit)) : Unit {
|
||||
let size = 1 <<< N;
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Jupyter.Core;
|
||||
using Microsoft.Quantum.IQSharp;
|
||||
using Microsoft.Quantum.IQSharp.Common;
|
||||
using Microsoft.Quantum.Simulation.Common;
|
||||
using Microsoft.Quantum.Simulation.Core;
|
||||
|
||||
namespace Microsoft.Quantum.Katas
|
||||
{
|
||||
public class CheckKataMagic : MagicSymbol
|
||||
{
|
||||
/// <summary>
|
||||
/// IQ# Magic that checks that the reference implementation of a Kata's test runs successfully.
|
||||
/// </summary>
|
||||
public CheckKataMagic(IOperationResolver resolver, ICompilerService compiler, ILogger<KataMagic> logger)
|
||||
{
|
||||
this.Name = $"%check_kata";
|
||||
this.Documentation = new Documentation() { Summary = "Checks the resference implementaiton of a single kata's test." };
|
||||
this.Kind = SymbolKind.Magic;
|
||||
this.Execute = this.Run;
|
||||
|
||||
this.Resolver = resolver;
|
||||
this.Compiler = compiler;
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Resolver lets us find compiled Q# operations from the workspace
|
||||
/// </summary>
|
||||
protected IOperationResolver Resolver { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of user-defined Q# code snippets from the notebook.
|
||||
/// </summary>
|
||||
protected ICompilerService Compiler { get; }
|
||||
|
||||
protected ILogger<KataMagic> Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// What this Magic does when triggered. It will:
|
||||
/// - find the Test to execute based on the provided name,
|
||||
/// - semi-compile the code after to identify the name of the operation with the user's answer.
|
||||
/// - call simulate to execute the test.
|
||||
/// </summary>
|
||||
public virtual ExecutionResult Run(string input, IChannel channel)
|
||||
{
|
||||
channel = channel.WithNewLines();
|
||||
|
||||
// Expect exactly two arguments, the name of the Kata and the user's answer (code).
|
||||
var args = input?.Split(new char[] { ' ', '\n', '\t' }, 2);
|
||||
if (args == null || args.Length != 2)
|
||||
{
|
||||
channel.Stderr("Invalid parameters. Usage: `%kata Test \"Q# operation\"`");
|
||||
return ExecuteStatus.Error.ToExecutionResult();
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
var code = args[1];
|
||||
|
||||
var test = FindTest(name);
|
||||
if (test == null)
|
||||
{
|
||||
channel.Stderr($"Invalid test name: {name}");
|
||||
return ExecuteStatus.Error.ToExecutionResult();
|
||||
}
|
||||
|
||||
var userAnswer = Compile(code, channel);
|
||||
if (userAnswer == null) { return ExecuteStatus.Error.ToExecutionResult(); }
|
||||
|
||||
return Simulate(test, userAnswer, channel)
|
||||
? "Success!".ToExecutionResult()
|
||||
: ExecuteStatus.Error.ToExecutionResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compiles the given code. Checks there is only one operation defined in the code,
|
||||
/// and returns its corresponding OperationInfo
|
||||
/// </summary>
|
||||
public virtual string Compile(string code, IChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = Compiler.IdentifyElements(code);
|
||||
|
||||
// Gets the names of all the operations found for this snippet
|
||||
var opsNames =
|
||||
result
|
||||
.Where(e => e.IsQsCallable)
|
||||
.Select(e => e.ToFullName().WithoutNamespace(Microsoft.Quantum.IQSharp.Snippets.SNIPPETS_NAMESPACE))
|
||||
.OrderBy(o => o)
|
||||
.ToArray();
|
||||
|
||||
if (opsNames.Length > 1)
|
||||
{
|
||||
channel.Stdout("Expecting only one Q# operation in code. Using the first one");
|
||||
}
|
||||
|
||||
return opsNames.First();
|
||||
}
|
||||
catch (CompilationErrorsException c)
|
||||
{
|
||||
foreach (var m in c.Errors) channel.Stderr(m);
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger?.LogWarning(e, "Unexpected error.");
|
||||
channel.Stderr(e.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the given test by replacing the userAnswer with its reference implementation.
|
||||
/// It is expected that the test will succeed with no warnings.
|
||||
/// </summary>
|
||||
public virtual bool Simulate(OperationInfo test, string userAnswer, IChannel channel)
|
||||
{
|
||||
// The skeleton answer used to compile the workspace
|
||||
var skeletonAnswer = FindSkeletonAnswer(test, userAnswer);
|
||||
if (skeletonAnswer == null)
|
||||
{
|
||||
channel.Stderr($"Invalid task name: {userAnswer}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The reference implementation
|
||||
var referenceAnswer = FindReferenceImplementation(test, userAnswer);
|
||||
if (referenceAnswer == null)
|
||||
{
|
||||
channel.Stderr($"Reference answer not found: {userAnswer}");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var qsim = CreateSimulator();
|
||||
var hasWarnings = false;
|
||||
|
||||
qsim.DisableLogToConsole();
|
||||
qsim.Register(skeletonAnswer.RoslynType, referenceAnswer.RoslynType, typeof(ICallable));
|
||||
qsim.OnLog += (msg) =>
|
||||
{
|
||||
hasWarnings = msg?.StartsWith("[WARNING]") ?? hasWarnings;
|
||||
channel.Stdout(msg);
|
||||
};
|
||||
|
||||
var value = test.RunAsync(qsim, null).Result;
|
||||
|
||||
if (qsim is IDisposable dis) { dis.Dispose(); }
|
||||
|
||||
return !hasWarnings;
|
||||
}
|
||||
catch (AggregateException agg)
|
||||
{
|
||||
foreach (var e in agg.InnerExceptions) { channel.Stderr(e.Message); }
|
||||
channel.Stderr($"Try again!");
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
channel.Stderr(e.Message);
|
||||
channel.Stderr($"Try again!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the instance of the simulator to use to run the test
|
||||
/// (for now always CounterSimulator from the same package).
|
||||
/// </summary>
|
||||
public virtual SimulatorBase CreateSimulator() =>
|
||||
new CounterSimulator();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OperationInfo for the test to run.
|
||||
/// </summary>
|
||||
public virtual OperationInfo FindTest(string testName) =>
|
||||
Resolver.Resolve(testName);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the original shell for the test's answer in the workspace for the given userAnswer.
|
||||
/// It does this by finding another operation with the same name as the `userAnswer` but in the
|
||||
/// test's namespace
|
||||
/// </summary>
|
||||
public virtual OperationInfo FindSkeletonAnswer(OperationInfo test, string userAnswer) =>
|
||||
Resolver.Resolve($"{test.Header.QualifiedName.Namespace.Value}.{userAnswer}");
|
||||
|
||||
/// <summary>
|
||||
/// Returns the reference implementation for the test's answer in the workspace for the given userAnswer.
|
||||
/// It does this by finding another operation with the same name as the `userAnswer` but in the
|
||||
/// test's namespace and with <c>_Reference</c> added to the userAnswer's name.
|
||||
/// </summary>
|
||||
public virtual OperationInfo FindReferenceImplementation(OperationInfo test, string userAnswer) =>
|
||||
Resolver.Resolve($"{test.Header.QualifiedName.Namespace.Value}.{userAnswer}_Reference");
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.Quantum.Katas
|
|||
public KataMagic(IOperationResolver resolver, ISnippets snippets, ILogger<KataMagic> logger)
|
||||
{
|
||||
this.Name = $"%kata";
|
||||
this.Documentation = new Documentation() { Summary = "Executes a single kata.", Full = "## Executes a single kata.\n##Usage: \n%kata Test \"q# operation\"" };
|
||||
this.Documentation = new Documentation() { Summary = "Executes a single test.", Full = "## Executes a single test.\n##Usage: \n%kata Test \"q# operation\"" };
|
||||
this.Kind = SymbolKind.Magic;
|
||||
this.Execute = this.Run;
|
||||
|
||||
|
@ -43,9 +43,9 @@ namespace Microsoft.Quantum.Katas
|
|||
|
||||
/// <summary>
|
||||
/// What this Magic does when triggered. It will:
|
||||
/// - find the Kata to execute based on the Kata name,
|
||||
/// - find the Test to execute based on the given name,
|
||||
/// - compile the code after found after the name as the user's answer.
|
||||
/// - run (simulate) the kata.
|
||||
/// - run (simulate) the test and report its result.
|
||||
/// </summary>
|
||||
public virtual ExecutionResult Run(string input, IChannel channel)
|
||||
{
|
||||
|
@ -62,8 +62,8 @@ namespace Microsoft.Quantum.Katas
|
|||
var name = args[0];
|
||||
var code = args[1];
|
||||
|
||||
var kata = FindKata(name);
|
||||
if (kata == null)
|
||||
var test = FindTest(name);
|
||||
if (test == null)
|
||||
{
|
||||
channel.Stderr($"Invalid test name: {name}");
|
||||
return ExecuteStatus.Error.ToExecutionResult();
|
||||
|
@ -72,7 +72,7 @@ namespace Microsoft.Quantum.Katas
|
|||
var userAnswer = Compile(code, channel);
|
||||
if (userAnswer == null) { return ExecuteStatus.Error.ToExecutionResult(); }
|
||||
|
||||
return Simulate(kata, userAnswer, channel)
|
||||
return Simulate(test, userAnswer, channel)
|
||||
? "Success!".ToExecutionResult()
|
||||
: ExecuteStatus.Error.ToExecutionResult();
|
||||
}
|
||||
|
@ -123,10 +123,10 @@ namespace Microsoft.Quantum.Katas
|
|||
/// (by calling `FindRawAnswer`) and replace its implementation with the userAnswer
|
||||
/// in the simulator.
|
||||
/// </summary>
|
||||
public virtual bool Simulate(OperationInfo kata, OperationInfo userAnswer, IChannel channel)
|
||||
public virtual bool Simulate(OperationInfo test, OperationInfo userAnswer, IChannel channel)
|
||||
{
|
||||
var rawAnswer = FindRawAnswer(kata, userAnswer);
|
||||
if (rawAnswer == null)
|
||||
var skeletonAnswer = FindSkeletonAnswer(test, userAnswer);
|
||||
if (skeletonAnswer == null)
|
||||
{
|
||||
channel.Stderr($"Invalid task: {userAnswer.FullName}");
|
||||
return false;
|
||||
|
@ -137,10 +137,10 @@ namespace Microsoft.Quantum.Katas
|
|||
var qsim = CreateSimulator();
|
||||
|
||||
qsim.DisableLogToConsole();
|
||||
qsim.Register(rawAnswer.RoslynType, userAnswer.RoslynType, typeof(ICallable));
|
||||
qsim.Register(skeletonAnswer.RoslynType, userAnswer.RoslynType, typeof(ICallable));
|
||||
qsim.OnLog += channel.Stdout;
|
||||
|
||||
var value = kata.RunAsync(qsim, null).Result;
|
||||
var value = test.RunAsync(qsim, null).Result;
|
||||
|
||||
if (qsim is IDisposable dis) { dis.Dispose(); }
|
||||
|
||||
|
@ -161,25 +161,25 @@ namespace Microsoft.Quantum.Katas
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the instance of the simulator to use to run the Kata
|
||||
/// Creates the instance of the simulator to use to run the Test
|
||||
/// (for now always CounterSimulator from the same package).
|
||||
/// </summary>
|
||||
public virtual SimulatorBase CreateSimulator() =>
|
||||
new CounterSimulator();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OperationInfo for the Kata to run.
|
||||
/// Returns the OperationInfo with the Test to run based on the given name.
|
||||
/// </summary>
|
||||
public virtual OperationInfo FindKata(string kataName) =>
|
||||
Resolver.Resolve(kataName);
|
||||
public virtual OperationInfo FindTest(string testName) =>
|
||||
Resolver.Resolve(testName);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the original shell for the Kata's answer in the workspace for the given userAnswer.
|
||||
/// Returns the original shell for the test's answer in the workspace for the given userAnswer.
|
||||
/// It does this by finding another operation with the same name as the `userAnswer` but in the
|
||||
/// Kata's namespace
|
||||
/// test's namespace
|
||||
/// </summary>
|
||||
public virtual OperationInfo FindRawAnswer(OperationInfo kata, OperationInfo userAnswer) =>
|
||||
Resolver.Resolve($"{kata.Header.QualifiedName.Namespace.Value}.{userAnswer.FullName}");
|
||||
public virtual OperationInfo FindSkeletonAnswer(OperationInfo test, OperationInfo userAnswer) =>
|
||||
Resolver.Resolve($"{test.Header.QualifiedName.Namespace.Value}.{userAnswer.FullName}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Jupyter.Core" Version="1.1.13141" />
|
||||
<PackageReference Include="Microsoft.Quantum.IQSharp.Core" Version="0.5.1904.1302" />
|
||||
<PackageReference Include="Microsoft.Quantum.IQSharp.Core" Version="0.6.1905.301" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче