Add DistinguishUnitaries kata (#378)
This commit is contained in:
Родитель
2cac1c9c85
Коммит
9ce81ce60e
|
@ -0,0 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>Quantum.Kata.DistinguishUnitaries</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Quantum.Standard" Version="0.11.2006.403" />
|
||||
<PackageReference Include="Microsoft.Quantum.Development.Kit" Version="0.11.2006.403" />
|
||||
<PackageReference Include="Microsoft.Quantum.Xunit" Version="0.11.2006.403" />
|
||||
<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" />
|
||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\utilities\Common\Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,286 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Distinguish Unitaries Kata\n",
|
||||
"\n",
|
||||
"The **Distinguish Unitaries** quantum kata offers tasks in which you are given a unitary and have to figure out which of the list it is by designing and performing experiments on it.\n",
|
||||
"\n",
|
||||
"Each task is wrapped in one operation preceded by the description of the task.\n",
|
||||
"Your goal is to fill in the blank (marked with `// ...` comments)\n",
|
||||
"with some Q# code that solves the task. To verify your answer, run the cell using Ctrl/⌘+Enter.\n",
|
||||
"\n",
|
||||
"The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To begin, first prepare this notebook for execution (if you skip the first step, you'll get \"Syntax does not match any known patterns\" error when you try to execute Q# code in the next cells; if you skip the second step, you'll get \"Invalid test name\" error):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%package Microsoft.Quantum.Katas::0.11.2006.403"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> 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.1.2.3, 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.1.2.3\n",
|
||||
"> 4. Reinstall the kernel:\n",
|
||||
"> dotnet iqsharp install\n",
|
||||
"> 5. Restart the Notebook.\n",
|
||||
"> </details>\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%workspace reload"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part I. Single-Qubit Gates"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.1. Identity or Pauli X?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the identity (**I** gate)\n",
|
||||
"or the Pauli X gate (**X** gate). \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **I** gate, 1 if the given operation is the **X** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T11_DistinguishIfromX_Test \n",
|
||||
"\n",
|
||||
"operation DistinguishIfromX (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" // ...\n",
|
||||
" return -1;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"*Can't come up with a solution? See the explained solution in the [Distinguish Unitaries Workbook](./Workbook_DistinguishUnitaries.ipynb#Task-1.1.-Identity-or-Pauli-X?).*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.2. Identity or Pauli Z?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the identity (**I** gate)\n",
|
||||
"or the Pauli Z gate (**Z** gate). \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **I** gate, 1 if the given operation is the **Z** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T12_DistinguishIfromZ_Test \n",
|
||||
"\n",
|
||||
"operation DistinguishIfromZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" // ...\n",
|
||||
" return -1;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"*Can't come up with a solution? See the explained solution in the [Distinguish Unitaries Workbook](./Workbook_DistinguishUnitaries.ipynb#Task-1.2.-Identity-or-Pauli-Z?).*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.3. Z or S?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the **Z** gate\n",
|
||||
"or the **S** gate. \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **Z** gate, 1 if the given operation is the **S** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants at most **twice**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T13_DistinguishZfromS_Test \n",
|
||||
"\n",
|
||||
"operation DistinguishZfromS (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" // ...\n",
|
||||
" return -1;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"*Can't come up with a solution? See the explained solution in the [Distinguish Unitaries Workbook](./Workbook_DistinguishUnitaries.ipynb#Task-1.3.-Z-or-S?).*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.4. Z or -Z?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the **Z** gate\n",
|
||||
"or the minus **Z** gate (i.e., the gate $- |0\\rangle\\langle0| + |1\\rangle\\langle1|$). \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **Z** gate, 1 if the given operation is the **-Z** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T14_DistinguishZfromMinusZ_Test \n",
|
||||
"\n",
|
||||
"operation DistinguishZfromMinusZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" // ...\n",
|
||||
" return -1;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"*Can't come up with a solution? See the explained solution in the [Distinguish Unitaries Workbook](./Workbook_DistinguishUnitaries.ipynb#Task-1.4.-Z-or--Z?).*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part II. Multi-Qubit Gates"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 2.1. $I \\otimes X$ or CNOT?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the $I \\otimes X$ (the X gate applied to the second qubit)\n",
|
||||
"or the **CNOT** gate with the first qubit as control and the second qubit as target.\n",
|
||||
"* The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.\n",
|
||||
"* The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is $I \\otimes X$, 1 if the given operation is the **CNOT** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T21_DistinguishIXfromCNOT_Test\n",
|
||||
"\n",
|
||||
"operation DistinguishIXfromCNOT (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {\n",
|
||||
" // ...\n",
|
||||
" return -1;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"*Can't come up with a solution? See the explained solution in the [Distinguish Unitaries Workbook](./Workbook_DistinguishUnitaries.ipynb#Task-2.1.-$I-\\otimes-X$-or-CNOT?).*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"*To be continued...*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Q#",
|
||||
"language": "qsharp",
|
||||
"name": "iqsharp"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".qs",
|
||||
"mimetype": "text/x-qsharp",
|
||||
"name": "qsharp",
|
||||
"version": "0.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29926.136
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DistinguishUnitaries", "DistinguishUnitaries.csproj", "{F7A0175F-4217-4343-8A3C-EA68FAAB6B7B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "..\utilities\Common\Common.csproj", "{F8640A84-E48D-4C12-BB11-94E709003CE9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F7A0175F-4217-4343-8A3C-EA68FAAB6B7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F7A0175F-4217-4343-8A3C-EA68FAAB6B7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F7A0175F-4217-4343-8A3C-EA68FAAB6B7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F7A0175F-4217-4343-8A3C-EA68FAAB6B7B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F8640A84-E48D-4C12-BB11-94E709003CE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F8640A84-E48D-4C12-BB11-94E709003CE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F8640A84-E48D-4C12-BB11-94E709003CE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F8640A84-E48D-4C12-BB11-94E709003CE9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {4E22BDB7-FE55-4D1C-98FA-BD7612C8525D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,5 @@
|
|||
# Welcome!
|
||||
|
||||
The "Distinguish Unitaries" kata offers tasks in which you are given a unitary and have to figure out which of the list it is by designing and performing experiments on it.
|
||||
|
||||
You can [run the DistinguishUnitaries kata as a Jupyter Notebook](https://mybinder.org/v2/gh/Microsoft/QuantumKatas/master?filepath=DistinguishUnitaries%2FDistinguishUnitaries.ipynb)!
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains reference solutions to all tasks.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
// We recommend that you try to solve the tasks yourself first,
|
||||
// but feel free to look up the solution if you get stuck.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Quantum.Kata.DistinguishUnitaries {
|
||||
open Microsoft.Quantum.Arithmetic;
|
||||
open Microsoft.Quantum.Characterization;
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Measurement;
|
||||
open Microsoft.Quantum.Oracles;
|
||||
|
||||
// Task 1.1. Identity or Pauli X?
|
||||
// Output: 0 if the given operation is the I gate,
|
||||
// 1 if the given operation is the X gate.
|
||||
operation DistinguishIfromX_Reference (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// apply operation to the |0⟩ state and measure: |0⟩ means I, |1⟩ means X
|
||||
using (q = Qubit()) {
|
||||
unitary(q);
|
||||
return MResetZ(q) == Zero ? 0 | 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Task 1.2. Identity or Pauli Z?
|
||||
// Output: 0 if the given operation is the I gate,
|
||||
// 1 if the given operation is the Z gate.
|
||||
operation DistinguishIfromZ_Reference (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// apply operation to the |+⟩ state and measure: |+⟩ means I, |-⟩ means Z
|
||||
using (q = Qubit()) {
|
||||
H(q);
|
||||
unitary(q);
|
||||
H(q);
|
||||
return MResetZ(q) == Zero ? 0 | 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Task 1.3. Z or S?
|
||||
// Output: 0 if the given operation is the Z gate,
|
||||
// 1 if the given operation is the S gate.
|
||||
operation DistinguishZfromS_Reference (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// apply operation twice to |+⟩ state and measure: |+⟩ means Z, |-⟩ means S
|
||||
// X will end up as XXX = X, H will end up as HXH = Z (does not change |0⟩ state)
|
||||
using (q = Qubit()) {
|
||||
H(q);
|
||||
unitary(q);
|
||||
unitary(q);
|
||||
H(q);
|
||||
return MResetZ(q) == Zero ? 0 | 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Task 1.4. Z or -Z?
|
||||
// Output: 0 if the given operation is the Z gate,
|
||||
// 1 if the given operation is the -Z gate.
|
||||
operation DistinguishZfromMinusZ_Reference (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// apply Controlled unitary to (|0⟩ + |1⟩) ⊗ |0⟩ state: Z will leave it unchanged while -Z will make it into (|0⟩ + |1⟩) ⊗ |0⟩
|
||||
using (qs = Qubit[2]) {
|
||||
// prep (|0⟩ + |1⟩) ⊗ |0⟩
|
||||
H(qs[0]);
|
||||
|
||||
Controlled unitary(qs[0..0], qs[1]);
|
||||
|
||||
H(qs[0]);
|
||||
// |0⟩ means it was Z, |1⟩ means -Z
|
||||
|
||||
return MResetZ(qs[0]) == Zero ? 0 | 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part II. Multi-Qubit Gates
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. I ⊗ X or CNOT?
|
||||
// Output: 0 if the given operation is I ⊗ X,
|
||||
// 1 if the given operation is the CNOT gate.
|
||||
operation DistinguishIXfromCNOT_Reference (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {
|
||||
// apply to |00⟩ and measure 2nd qubit: CNOT will do nothing, I ⊗ X will change to |01⟩
|
||||
using (qs = Qubit[2]) {
|
||||
unitary(qs);
|
||||
return MResetZ(qs[1]) == One ? 0 | 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Quantum.Kata.DistinguishUnitaries {
|
||||
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Welcome!
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// "Distinguishing Unitaries" quantum kata is a series of exercises designed
|
||||
// to help you learn to think about unitary transformations in a different way.
|
||||
// It covers figuring out ways to distinguish several unitaries from the given list
|
||||
// by performing experiments on them.
|
||||
|
||||
// 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,
|
||||
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
|
||||
// with some Q# code to make the failing test pass.
|
||||
|
||||
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part I. Single-Qubit Gates
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 1.1. Identity or Pauli X?
|
||||
// Input: An operation that implements a single-qubit unitary transformation:
|
||||
// either the identity (I gate)
|
||||
// or the Pauli X gate (X gate).
|
||||
// The operation will have Adjoint and Controlled variants defined.
|
||||
// Output: 0 if the given operation is the I gate,
|
||||
// 1 if the given operation is the X gate.
|
||||
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
|
||||
operation DistinguishIfromX (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// ...
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.2. Identity or Pauli Z?
|
||||
// Input: An operation that implements a single-qubit unitary transformation:
|
||||
// either the identity (I gate)
|
||||
// or the Pauli Z gate (Z gate).
|
||||
// The operation will have Adjoint and Controlled variants defined.
|
||||
// Output: 0 if the given operation is the I gate,
|
||||
// 1 if the given operation is the Z gate.
|
||||
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
|
||||
operation DistinguishIfromZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// ...
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.3. Z or S?
|
||||
// Input: An operation that implements a single-qubit unitary transformation:
|
||||
// either the Pauli Z gate
|
||||
// or the S gate.
|
||||
// The operation will have Adjoint and Controlled variants defined.
|
||||
// Output: 0 if the given operation is the Z gate,
|
||||
// 1 if the given operation is the S gate.
|
||||
// You are allowed to apply the given operation and its adjoint/controlled variants at most twice.
|
||||
operation DistinguishZfromS (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// ...
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Task 1.4. Z or -Z?
|
||||
// Input: An operation that implements a single-qubit unitary transformation:
|
||||
// either the Pauli Z gate
|
||||
// or the minus Pauli Z gate (i.e., a gate -|0〉〈0| + |1〉〈1|).
|
||||
// The operation will have Adjoint and Controlled variants defined.
|
||||
// Output: 0 if the given operation is the Z gate,
|
||||
// 1 if the given operation is the -Z gate.
|
||||
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
|
||||
operation DistinguishZfromMinusZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
|
||||
// ...
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part II. Multi-Qubit Gates
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Task 2.1. I ⊗ X or CNOT?
|
||||
// Input: An operation that implements a two-qubit unitary transformation:
|
||||
// either I ⊗ X (the X gate applied to the second qubit)
|
||||
// or the CNOT gate with the first qubit as control and the second qubit as target.
|
||||
// The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
|
||||
// The operation will have Adjoint and Controlled variants defined.
|
||||
// Output: 0 if the given operation is I ⊗ X,
|
||||
// 1 if the given operation is the CNOT gate.
|
||||
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
|
||||
operation DistinguishIXfromCNOT (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {
|
||||
// ...
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains parts of the testing harness.
|
||||
// You should not modify anything in this file.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
using Microsoft.Quantum.Simulation.XUnit;
|
||||
using Xunit.Abstractions;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Microsoft.Quantum.Katas;
|
||||
|
||||
namespace Quantum.Kata.DistinguishUnitaries
|
||||
{
|
||||
public class TestSuiteRunner
|
||||
{
|
||||
private readonly ITestOutputHelper output;
|
||||
|
||||
public TestSuiteRunner(ITestOutputHelper output)
|
||||
{
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This driver will run all Q# tests (operations named "...Test")
|
||||
/// that belong to namespace Quantum.Kata.DistinguishUnitaries.
|
||||
/// </summary>
|
||||
[OperationDriver(TestNamespace = "Quantum.Kata.DistinguishUnitaries")]
|
||||
public void TestTarget(TestOperation op)
|
||||
{
|
||||
using (var sim = new CounterSimulator())
|
||||
{
|
||||
// OnLog defines action(s) performed when Q# test calls function Message
|
||||
sim.OnLog += (msg) => { output.WriteLine(msg); };
|
||||
sim.OnLog += (msg) => { Debug.WriteLine(msg); };
|
||||
op.TestOperationRunner(sim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// This file contains testing harness for all tasks.
|
||||
// You should not modify anything in this file.
|
||||
// The tasks themselves can be found in Tasks.qs file.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Quantum.Kata.DistinguishUnitaries {
|
||||
open Microsoft.Quantum.Intrinsic;
|
||||
open Microsoft.Quantum.Canon;
|
||||
open Microsoft.Quantum.Diagnostics;
|
||||
open Microsoft.Quantum.Convert;
|
||||
open Microsoft.Quantum.Math;
|
||||
open Microsoft.Quantum.Measurement;
|
||||
open Microsoft.Quantum.Arrays;
|
||||
|
||||
open Quantum.Kata.Utils;
|
||||
|
||||
// "Framework" operation for testing tasks for distinguishing unitaries
|
||||
// "unitaries" is the list of unitaries that can be passed to the task
|
||||
// "testImpl" - the solution to be tested
|
||||
// "maxCalls" - max # of calls to the unitary that are allowed (-1 means unlimited)
|
||||
operation DistinguishUnitaries_Framework<'UInput> (
|
||||
unitaries : ('UInput => Unit is Adj+Ctl)[],
|
||||
testImpl : (('UInput => Unit is Adj+Ctl) => Int),
|
||||
maxCalls : Int) : Unit {
|
||||
|
||||
let nUnitaries = Length(unitaries);
|
||||
let nTotal = 100;
|
||||
mutable wrongClassifications = new Int[nUnitaries * nUnitaries]; // [i * nU + j] number of times unitary i was classified as j
|
||||
mutable unknownClassifications = new Int[nUnitaries]; // number of times unitary i was classified as something unknown
|
||||
|
||||
for (i in 1 .. nTotal) {
|
||||
// get a random integer to define the unitary used
|
||||
let actualIndex = RandomInt(nUnitaries);
|
||||
|
||||
ResetOracleCallsCount();
|
||||
|
||||
// get the solution's answer and verify that it's a match
|
||||
let returnedIndex = testImpl(unitaries[actualIndex]);
|
||||
|
||||
// check the constraint on the number of allowed calls to the unitary
|
||||
// note that a unitary can be implemented as Controlled on |1⟩, so we need to count variants as well
|
||||
if (maxCalls > 0) {
|
||||
let actualCalls = GetOracleCallsCount(unitaries[actualIndex]) +
|
||||
GetOracleCallsCount(Adjoint unitaries[actualIndex]) +
|
||||
GetOracleCallsCount(Controlled unitaries[actualIndex]);
|
||||
if (actualCalls > maxCalls) {
|
||||
fail $"You are allowed to do at most {maxCalls} calls, and you did {actualCalls}";
|
||||
}
|
||||
}
|
||||
|
||||
if (returnedIndex != actualIndex) {
|
||||
if (returnedIndex < 0 or returnedIndex >= nUnitaries) {
|
||||
set unknownClassifications w/= actualIndex <- unknownClassifications[actualIndex] + 1;
|
||||
} else {
|
||||
let index = actualIndex * nUnitaries + returnedIndex;
|
||||
set wrongClassifications w/= index <- wrongClassifications[index] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutable totalMisclassifications = 0;
|
||||
for (i in 0 .. nUnitaries - 1) {
|
||||
for (j in 0 .. nUnitaries - 1) {
|
||||
let misclassifiedIasJ = wrongClassifications[(i * nUnitaries) + j];
|
||||
if (misclassifiedIasJ != 0) {
|
||||
set totalMisclassifications += misclassifiedIasJ;
|
||||
Message($"Misclassified {i} as {j} in {misclassifiedIasJ} test runs.");
|
||||
}
|
||||
}
|
||||
if (unknownClassifications[i] != 0) {
|
||||
set totalMisclassifications += unknownClassifications[i];
|
||||
Message($"Misclassified {i} as unknown unitary in {unknownClassifications[i]} test runs.");
|
||||
}
|
||||
}
|
||||
// This check will tell the total number of failed classifications
|
||||
Fact(totalMisclassifications == 0, $"{totalMisclassifications} test runs out of {nTotal} returned incorrect state.");
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// A pair of helper wrappers used to differentiate the unitary we pass as an argument from gates used normally
|
||||
operation SingleQubitGateWrapper (unitary : (Qubit => Unit is Adj+Ctl), register : Qubit) : Unit is Adj+Ctl {
|
||||
unitary(register);
|
||||
}
|
||||
|
||||
function SingleQubitGateAsUnitary (unitary : (Qubit => Unit is Adj+Ctl)) : (Qubit => Unit is Adj+Ctl) {
|
||||
return SingleQubitGateWrapper(unitary, _);
|
||||
}
|
||||
|
||||
|
||||
operation T11_DistinguishIfromX_Test () : Unit {
|
||||
DistinguishUnitaries_Framework(Mapped(SingleQubitGateAsUnitary, [I, X]), DistinguishIfromX, 1);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T12_DistinguishIfromZ_Test () : Unit {
|
||||
DistinguishUnitaries_Framework(Mapped(SingleQubitGateAsUnitary, [I, Z]), DistinguishIfromZ, 1);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation T13_DistinguishZfromS_Test () : Unit {
|
||||
DistinguishUnitaries_Framework(Mapped(SingleQubitGateAsUnitary, [Z, S]), DistinguishZfromS, 2);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
operation MinusOne (q : Qubit) : Unit is Adj+Ctl {
|
||||
within { X(q); }
|
||||
apply { Z(q); }
|
||||
Z(q);
|
||||
}
|
||||
|
||||
operation T14_DistinguishZfromMinusZ_Test () : Unit {
|
||||
DistinguishUnitaries_Framework(Mapped(SingleQubitGateAsUnitary, [Z, BoundCA([Z, MinusOne])]), DistinguishZfromMinusZ, 1);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Part II. Multi-Qubit Gates
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
operation IXWrapper (qs : Qubit[]) : Unit is Adj+Ctl {
|
||||
Fact(Length(qs) == 2, "This unitary can only be applied to arrays of length 2.");
|
||||
X(qs[1]);
|
||||
}
|
||||
|
||||
operation CNOTWrapper (qs : Qubit[]) : Unit is Adj+Ctl {
|
||||
Fact(Length(qs) == 2, "This unitary can only be applied to arrays of length 2.");
|
||||
CNOT(qs[0], qs[1]);
|
||||
}
|
||||
|
||||
operation T21_DistinguishIXfromCNOT_Test () : Unit {
|
||||
DistinguishUnitaries_Framework([IXWrapper, CNOTWrapper], DistinguishIXfromCNOT, 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,422 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Distinguish Unitaries Kata Workbook\n",
|
||||
"\n",
|
||||
"**What is this workbook?**\n",
|
||||
"A workbook is a collection of problems, accompanied by solutions to them. \n",
|
||||
"The explanations focus on the logical steps required to solve a problem; they illustrate the concepts that need to be applied to come up with a solution to the problem, explaining the mathematical steps required. \n",
|
||||
"\n",
|
||||
"Note that a workbook should not be the primary source of knowledge on the subject matter; it assumes that you've already read a tutorial or a textbook and that you are now seeking to improve your problem-solving skills. You should attempt solving the tasks of the respective kata first, and turn to the workbook only if stuck. While a textbook emphasizes knowledge acquisition, a workbook emphasizes skill acquisition.\n",
|
||||
"\n",
|
||||
"This workbook describes the solutions to the problems offered in the [Distinguish Unitaries kata](./DistinguishUnitaries.ipynb). Since the tasks are offered as programming problems, the explanations also cover some elements of Q# that might be non-obvious for a first-time user.\n",
|
||||
"\n",
|
||||
"**What you should know for this workbook**\n",
|
||||
"\n",
|
||||
"You should be familiar with the following concepts before tackling the Distinguish Unitaries kata (and this workbook):\n",
|
||||
"\n",
|
||||
"1. [Basic linear algebra](./../tutorials/LinearAlgebra/LinearAlgebra.ipynb)).\n",
|
||||
"2. [The concept of qubit](./../tutorials/Qubit/Qubit.ipynb) and [multi-qubit systems](./../tutorials/MultiQubitSystems/MultiQubitSystems.ipynb).\n",
|
||||
"3. [Single-qubit](./../tutorials/SingleQubitGates/SingleQubitGates.ipynb) and [multi-qubit quantum gates](./../tutorials/MultiQubitGates/MultiQubitGates.ipynb) and using them to manipulate the state of the system.\n",
|
||||
"4. Measurements and using them to distinguish quantum states."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To begin, first prepare this notebook for execution (if you skip the first step, you'll get \"Syntax does not match any known patterns\" error when you try to execute Q# code in the next cells; if you skip the second step, you'll get \"Invalid test name\" error):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%package Microsoft.Quantum.Katas::0.11.2006.403"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%workspace reload"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part I. Single-Qubit Gates"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.1. Identity or Pauli X?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the identity (**I** gate)\n",
|
||||
"or the Pauli X gate (**X** gate). \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **I** gate, 1 if the given operation is the **X** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Solution\n",
|
||||
"\n",
|
||||
"The only way to extract information out of a quantum system is measurement. \n",
|
||||
"Measurements give us information about the states of a system, so to get information about the gate, we need to find a way to convert it into information about a state.\n",
|
||||
"If we want to distinguish two gates, we need to figure out to prepare a state and perform a measurement on it that will give us a result that we can interpret.\n",
|
||||
"To do this, we’ll need to find a qubit state that, by applying to it I gate or X gate, will be transformed into states that can be distinguished using measurement, i.e., orthogonal states. \n",
|
||||
"Let's find such state.\n",
|
||||
"\n",
|
||||
"> As a reminder, here are the matrices that correspond to the given gates:\n",
|
||||
"> $$I = \\begin{bmatrix} 1 & 0 \\\\ 0 & 1 \\end{bmatrix}, X = \\begin{bmatrix} 0 & 1 \\\\ 1 & 0 \\end{bmatrix}$$\n",
|
||||
"\n",
|
||||
"Consider the effects of these gates on the basis states: \n",
|
||||
"\n",
|
||||
"$$I|0\\rangle = |0\\rangle, I|1\\rangle = |1\\rangle$$\n",
|
||||
"$$X|0\\rangle = |1\\rangle, X|1\\rangle = |0\\rangle$$\n",
|
||||
"\n",
|
||||
"We see that the **I** gate leaves the $|0\\rangle$ state unchanged, and the **X** gate transforms it into the $|1\\rangle$ state. \n",
|
||||
"So the easiest thing to do is to prepare a $|0\\rangle$ state, apply the given unitary to it and measure the resulting state in the computational basis:\n",
|
||||
"* If the measurement result is `Zero`, the measured state was $|0\\rangle$, and we know the unitary applied to it was the **I** gate.\n",
|
||||
"* If the measurement result is `One`, the measured state was $|1\\rangle$, and we know the unitary applied to it was the **X** gate.\n",
|
||||
"\n",
|
||||
"> In Q#, the freshly allocated qubits start in the $|0\\rangle$ state, so you don't need to do anything to prepare the necessary state before applying the unitary to it.\n",
|
||||
"> You also have to return the qubits you allocated to the $|0\\rangle$ state before releasing them. \n",
|
||||
"> You can do that by measuring the qubit using the `M` operation and applying the **X** gate if it was measured in the $|1\\rangle$ state, or you can use [`MResetZ`](https://docs.microsoft.com/en-us/qsharp/api/qsharp/microsoft.quantum.measurement.mresetz) operation that wraps this measurement and fixup into one operation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T11_DistinguishIfromX_Test \n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Measurement;\n",
|
||||
"\n",
|
||||
"operation DistinguishIfromX (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" using (q = Qubit()) {\n",
|
||||
" unitary(q);\n",
|
||||
" return MResetZ(q) == Zero ? 0 | 1;\n",
|
||||
" }\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[Return to task 1.1 of the Distinguish Unitaries kata.](./DistinguishUnitaries.ipynb#Task-1.1.-Identity-or-Pauli-X?)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.2. Identity or Pauli Z?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the identity (**I** gate)\n",
|
||||
"or the Pauli Z gate (**Z** gate). \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **I** gate, 1 if the given operation is the **Z** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Solution\n",
|
||||
"\n",
|
||||
"> As a reminder, $Z = \\begin{bmatrix} 1 & 0 \\\\ 0 & -1 \\end{bmatrix}$\n",
|
||||
"\n",
|
||||
"We won't be able to distinguish **I** from **Z** by applying them to the basis states, since they both leave the $|0\\rangle$ state unchanged and add a phase to the $|1\\rangle$ state: \n",
|
||||
"\n",
|
||||
"$$I|0\\rangle = |0\\rangle, I|1\\rangle = |1\\rangle$$\n",
|
||||
"$$Z|0\\rangle = |0\\rangle, Z|1\\rangle = -|1\\rangle$$\n",
|
||||
"\n",
|
||||
"However, if we try applying these gates to a superposition of basis states, we'll start seeing a difference between the resulting states:\n",
|
||||
"\n",
|
||||
"$$I \\big(\\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle)\\big) = \\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle)$$\n",
|
||||
"$$Z \\big(\\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle)\\big) = \\frac{1}{\\sqrt2}(|0\\rangle \\color{blue}{-} |1\\rangle)$$\n",
|
||||
"\n",
|
||||
"These two states are orthogonal and can be distinguished by measuring them in the $\\{ |+\\rangle, |-\\rangle\\}$ basis using [`MResetX`](https://docs.microsoft.com/en-us/qsharp/api/qsharp/microsoft.quantum.measurement.mresetx) operation (which is equivalent to applying an **H** gate and measuring in the computational basis).\n",
|
||||
"\n",
|
||||
"> The task of distinguishing these two states is covered in more detail in the [Measurements kata](./..//Measurements/Measurements.ipynb#Task-1.3.-$|+\\rangle$-or-$|-\\rangle$?) and the corresponding workbook."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T12_DistinguishIfromZ_Test \n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Measurement;\n",
|
||||
"\n",
|
||||
"operation DistinguishIfromZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" using (q = Qubit()) {\n",
|
||||
" H(q);\n",
|
||||
" unitary(q);\n",
|
||||
" return MResetX(q) == Zero ? 0 | 1;\n",
|
||||
" }\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[Return to task 1.2 of the Distinguish Unitaries kata.](./DistinguishUnitaries.ipynb#Task-1.2.-Identity-or-Pauli-Z?)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.3. Z or S?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the **Z** gate\n",
|
||||
"or the **S** gate. \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **Z** gate, 1 if the given operation is the **S** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants at most **twice**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Solution\n",
|
||||
"\n",
|
||||
"> As a reminder, $S = \\begin{bmatrix} 1 & 0 \\\\ 0 & i \\end{bmatrix}$\n",
|
||||
"\n",
|
||||
"This task differs from the previous two in that it allows you to apply the given unitary **twice**. \n",
|
||||
"Let's treat this as a hint that it is, and check how the given gates looks when applied twice. \n",
|
||||
"If you square the corresponding matrices (which is quite simple to do for diagonal matrices), you'll get\n",
|
||||
"\n",
|
||||
"$$Z^2 = \\begin{bmatrix} 1 & 0 \\\\ 0 & 1 \\end{bmatrix} = I, S^2 = \\begin{bmatrix} 1 & 0 \\\\ 0 & -1 \\end{bmatrix} = Z$$\n",
|
||||
"\n",
|
||||
"This means that the task of identifying the *square* of the given unitary transformation is the same as distinguishing **I** from **Z** gates - and that's exactly the [task 1.2](#Task-1.2.-Identity-or-Pauli-Z?)!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T13_DistinguishZfromS_Test \n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Measurement;\n",
|
||||
"\n",
|
||||
"operation DistinguishZfromS (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" using (q = Qubit()) {\n",
|
||||
" H(q);\n",
|
||||
" unitary(q);\n",
|
||||
" unitary(q);\n",
|
||||
" return MResetX(q) == Zero ? 0 | 1;\n",
|
||||
" }\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[Return to task 1.3 of the Distinguish Unitaries kata.](./DistinguishUnitaries.ipynb#Task-1.3.-Z-or-S?)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 1.4. Z or $-$Z?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the **Z** gate\n",
|
||||
"or the minus **Z** gate (i.e., the gate $- |0\\rangle\\langle0| + |1\\rangle\\langle1|$). \n",
|
||||
"The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is the **Z** gate, 1 if the given operation is the $-$**Z** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Solution\n",
|
||||
"\n",
|
||||
"This task is more interesting: the given gates differ by a global phase they introduce (i.e., each of them is a multiple of the other), and the results of applying them to any single-qubit state are going to be indistinguishable by any measurement you can devise.\n",
|
||||
"\n",
|
||||
"Fortunately, we are given not just the unitary itself, but also its controlled variant, i.e., the gate which applies the given unitary if the control qubit or qubits are in the $|1\\rangle$ state, and does nothing if they are in the $|0\\rangle$ state.\n",
|
||||
"This allows us to use so called \"phase kickback\" trick, in which applying a controlled version of a gate allows us to observe the phase introduced by this gate on the control qubit. Indeed,\n",
|
||||
"\n",
|
||||
"| State | Controlled Z | Controlled $-$Z |\n",
|
||||
"|-------|---------------|------|\n",
|
||||
"| $|00\\rangle$ | $|00\\rangle$ | $|00\\rangle$ |\n",
|
||||
"| $|01\\rangle$ | $|01\\rangle$ | $|01\\rangle$ |\n",
|
||||
"| $|10\\rangle$ | $\\color{blue}{|10\\rangle}$ | $\\color{blue}{-|10\\rangle}$ |\n",
|
||||
"| $|11\\rangle$ | $\\color{blue}{-|11\\rangle}$ | $\\color{blue}{|11\\rangle}$ |\n",
|
||||
"\n",
|
||||
"We see that both controlled gates don't modify the states with the control qubit in the $|0\\rangle$ state, but if the control qubit is in the $|1\\rangle$ state, they introduce a $-1$ phase to different basis states. \n",
|
||||
"We can take advantage of this if we apply the controlled gate to a state in which the *control qubit* is in superposition, such as $\\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle) \\otimes |0\\rangle$:\n",
|
||||
"\n",
|
||||
"$$\\text{Controlled Z}\\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle) \\otimes |0\\rangle = \\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle) \\otimes |0\\rangle$$\n",
|
||||
"$$\\text{Controlled }-\\text{Z}\\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle) \\otimes |0\\rangle = \\frac{1}{\\sqrt2}(|0\\rangle - |1\\rangle) \\otimes |0\\rangle$$\n",
|
||||
"\n",
|
||||
"After this we can measure the first qubit to distinguish $\\frac{1}{\\sqrt2}(|0\\rangle + |1\\rangle)$ from $\\frac{1}{\\sqrt2}(|0\\rangle - |1\\rangle)$, like we did in [task 1.2](#Task-1.2.-Identity-or-Pauli-Z?).\n",
|
||||
"\n",
|
||||
"> In Q# we can express controlled version of a gate using [Controlled functor](https://docs.microsoft.com/en-us/quantum/user-guide/using-qsharp/operations-functions#controlled-functor): the first argument of the resulting gate will be an array of control qubits, and the second one - the arguments of the original gate (in this case just the target qubit)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T14_DistinguishZfromMinusZ_Test \n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Measurement;\n",
|
||||
"\n",
|
||||
"operation DistinguishZfromMinusZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {\n",
|
||||
" using (qs = Qubit[2]) {\n",
|
||||
" // prep (|0⟩ + |1⟩) ⊗ |0⟩\n",
|
||||
" H(qs[0]);\n",
|
||||
"\n",
|
||||
" Controlled unitary(qs[0..0], qs[1]);\n",
|
||||
"\n",
|
||||
" return MResetX(qs[0]) == Zero ? 0 | 1;\n",
|
||||
" }\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[Return to task 1.4 of the Distinguish Unitaries kata.](./DistinguishUnitaries.ipynb#Task-1.4.-Z-or--Z?)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part II. Multi-Qubit Gates"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Task 2.1. $I \\otimes X$ or CNOT?\n",
|
||||
"\n",
|
||||
"**Input:** An operation that implements a single-qubit unitary transformation:\n",
|
||||
"either the $I \\otimes X$ (the **X** gate applied to the second qubit)\n",
|
||||
"or the **CNOT** gate with the first qubit as control and the second qubit as target.\n",
|
||||
"* The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.\n",
|
||||
"* The operation will have Adjoint and Controlled variants defined.\n",
|
||||
"\n",
|
||||
"**Output:** 0 if the given operation is $I \\otimes X$, 1 if the given operation is the **CNOT** gate.\n",
|
||||
"\n",
|
||||
"You are allowed to apply the given operation and its adjoint/controlled variants exactly **once**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Solution\n",
|
||||
"\n",
|
||||
"Let's consider the effect of these gates on the basis states:\n",
|
||||
"\n",
|
||||
"| State | $I \\otimes X$ | **CNOT** |\n",
|
||||
"|-------|---------------|------|\n",
|
||||
"| $|00\\rangle$ | $|01\\rangle$ | $|00\\rangle$ |\n",
|
||||
"| $|01\\rangle$ | $|00\\rangle$ | $|01\\rangle$ |\n",
|
||||
"| $|10\\rangle$ | $|11\\rangle$ | $|11\\rangle$ |\n",
|
||||
"| $|11\\rangle$ | $|10\\rangle$ | $|10\\rangle$ |\n",
|
||||
"\n",
|
||||
"We can see that applying these two gates to states with the first qubit in the $|1\\rangle$ state yields identical results, but applying them to states with the first qubit in the $|0\\rangle$ state produces states that differ in the second qubuit.\n",
|
||||
"This makes sense, since the **CNOT** gate is defined as \"apply **X** gate to the target qubit if the control qubit is in the $|1\\rangle$ state, and do nothing if it is in the $|0\\rangle$ state\".\n",
|
||||
"\n",
|
||||
"Thus, the easiest solution is: allocate two qubits in the $|00\\rangle$ state and apply the unitary to them, then measure the second qubit; if it is `One`, the gate is $I \\otimes X$, otherwise it's **CNOT**."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%kata T21_DistinguishIXfromCNOT_Test\n",
|
||||
"\n",
|
||||
"open Microsoft.Quantum.Measurement;\n",
|
||||
"\n",
|
||||
"operation DistinguishIXfromCNOT (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {\n",
|
||||
" using (qs = Qubit[2]) {\n",
|
||||
" unitary(qs);\n",
|
||||
" return MResetZ(qs[1]) == One ? 0 | 1;\n",
|
||||
" }\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[Return to task 2.1 of the Distinguish Unitaries kata.](./DistinguishUnitaries.ipynb#Task-2.1.-$I-\\otimes-X$-or-CNOT?)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"*To be continued...*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Q#",
|
||||
"language": "qsharp",
|
||||
"name": "iqsharp"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".qs",
|
||||
"mimetype": "text/x-qsharp",
|
||||
"name": "qsharp",
|
||||
"version": "0.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
|
@ -28,6 +28,7 @@ RUN cd ${HOME} && \
|
|||
./scripts/prebuild-kata.sh BasicGates && \
|
||||
./scripts/prebuild-kata.sh CHSHGame && \
|
||||
./scripts/prebuild-kata.sh DeutschJozsaAlgorithm && \
|
||||
./scripts/prebuild-kata.sh DistinguishUnitaries && \
|
||||
./scripts/prebuild-kata.sh GHZGame && \
|
||||
./scripts/prebuild-kata.sh GraphColoring && \
|
||||
./scripts/prebuild-kata.sh GroversAlgorithm && \
|
||||
|
|
|
@ -117,7 +117,9 @@ Each kata is a separate project that includes:
|
|||
Implement the BB84 key distribution algorithm.
|
||||
* **[Bit-flip error correcting code](./QEC_BitFlipCode/)**.
|
||||
Learn about a 3-qubit error correcting code for protecting against bit-flip errors.
|
||||
* **[Unitary Patterns*](./UnitaryPatterns/)**.
|
||||
* **[Distinguish Unitaries](./DistinguishUnitaries/)**.
|
||||
Learn to distinguish unitaries by designing and performing experiments with them.
|
||||
* **[Unitary Patterns](./UnitaryPatterns/)**.
|
||||
Learn to implement unitaries with matrices that follow certain patterns of zero and non-zero elements.
|
||||
|
||||
> For a Q# programming language quick reference sheet, see [Q# Language Quick Reference](./quickref/qsharp-quick-reference.pdf).
|
||||
|
|
|
@ -96,6 +96,8 @@
|
|||
" Implement the BB84 key distribution algorithm.\n",
|
||||
"* **[Bit-flip error correcting code](./QEC_BitFlipCode/QEC_BitFlipCode.ipynb)**.\n",
|
||||
" Learn about a 3-qubit error correcting code for protecting against bit-flip errors.\n",
|
||||
"* **[Distinguish Unitaries](./DistinguishUnitaries/DistinguishUnitaries.ipynb)**.\n",
|
||||
" Learn to distinguish unitaries by designing and performing experiments with them.\n",
|
||||
"* **[Unitary Patterns](./UnitaryPatterns/UnitaryPatterns.ipynb)**.\n",
|
||||
" Learn to implement unitaries with matrices that follow certain patterns of zero and non-zero elements.\n",
|
||||
"\n",
|
||||
|
|
Загрузка…
Ссылка в новой задаче