From 3c3f0d5543088ce01d8c18d6df170107fdd195f2 Mon Sep 17 00:00:00 2001 From: Mariia Mykhailova Date: Wed, 11 Jul 2018 16:35:59 -0700 Subject: [PATCH] First four katas --- .gitattributes | 6 + .gitignore | 597 ++++++++---------- BasicGates/.vscode/extensions.json | 7 + BasicGates/.vscode/tasks.json | 36 ++ BasicGates/BasicGates.csproj | 22 + BasicGates/BasicGates.sln | 25 + BasicGates/README.md | 14 + BasicGates/ReferenceImplementation.qs | 233 +++++++ BasicGates/Tasks.qs | 249 ++++++++ BasicGates/TestSuiteRunner.cs | 42 ++ BasicGates/Tests.qs | 268 ++++++++ DeutschJozsaAlgorithm/.vscode/extensions.json | 7 + DeutschJozsaAlgorithm/.vscode/tasks.json | 36 ++ .../DeutschJozsaAlgorithm.csproj | 22 + .../DeutschJozsaAlgorithm.sln | 25 + .../OracleCounterSimulator.cs | 94 +++ DeutschJozsaAlgorithm/README.md | 15 + .../ReferenceImplementation.qs | 373 +++++++++++ DeutschJozsaAlgorithm/Tasks.qs | 351 ++++++++++ DeutschJozsaAlgorithm/TestSuiteRunner.cs | 43 ++ DeutschJozsaAlgorithm/Tests.qs | 348 ++++++++++ Measurements/.vscode/extensions.json | 7 + Measurements/.vscode/tasks.json | 36 ++ Measurements/Measurements.csproj | 22 + Measurements/Measurements.sln | 25 + Measurements/README.md | 11 + Measurements/ReferenceImplementation.qs | 414 ++++++++++++ Measurements/Tasks.qs | 276 ++++++++ Measurements/TestSuiteRunner.cs | 42 ++ Measurements/Tests.qs | 533 ++++++++++++++++ README.md | 102 +++ Superposition/.vscode/extensions.json | 7 + Superposition/.vscode/tasks.json | 36 ++ Superposition/README.md | 12 + Superposition/ReferenceImplementation.qs | 320 ++++++++++ Superposition/Superposition.csproj | 22 + Superposition/Superposition.sln | 25 + Superposition/Tasks.qs | 194 ++++++ Superposition/TestSuiteRunner.cs | 42 ++ Superposition/Tests.qs | 240 +++++++ quickref/qsharp-quick-reference.pdf | Bin 0 -> 73056 bytes quickref/qsharp-quick-reference.tex | 262 ++++++++ 42 files changed, 5118 insertions(+), 323 deletions(-) create mode 100644 .gitattributes create mode 100644 BasicGates/.vscode/extensions.json create mode 100644 BasicGates/.vscode/tasks.json create mode 100644 BasicGates/BasicGates.csproj create mode 100644 BasicGates/BasicGates.sln create mode 100644 BasicGates/README.md create mode 100644 BasicGates/ReferenceImplementation.qs create mode 100644 BasicGates/Tasks.qs create mode 100644 BasicGates/TestSuiteRunner.cs create mode 100644 BasicGates/Tests.qs create mode 100644 DeutschJozsaAlgorithm/.vscode/extensions.json create mode 100644 DeutschJozsaAlgorithm/.vscode/tasks.json create mode 100644 DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.csproj create mode 100644 DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.sln create mode 100644 DeutschJozsaAlgorithm/OracleCounterSimulator.cs create mode 100644 DeutschJozsaAlgorithm/README.md create mode 100644 DeutschJozsaAlgorithm/ReferenceImplementation.qs create mode 100644 DeutschJozsaAlgorithm/Tasks.qs create mode 100644 DeutschJozsaAlgorithm/TestSuiteRunner.cs create mode 100644 DeutschJozsaAlgorithm/Tests.qs create mode 100644 Measurements/.vscode/extensions.json create mode 100644 Measurements/.vscode/tasks.json create mode 100644 Measurements/Measurements.csproj create mode 100644 Measurements/Measurements.sln create mode 100644 Measurements/README.md create mode 100644 Measurements/ReferenceImplementation.qs create mode 100644 Measurements/Tasks.qs create mode 100644 Measurements/TestSuiteRunner.cs create mode 100644 Measurements/Tests.qs create mode 100644 Superposition/.vscode/extensions.json create mode 100644 Superposition/.vscode/tasks.json create mode 100644 Superposition/README.md create mode 100644 Superposition/ReferenceImplementation.qs create mode 100644 Superposition/Superposition.csproj create mode 100644 Superposition/Superposition.sln create mode 100644 Superposition/Tasks.qs create mode 100644 Superposition/TestSuiteRunner.cs create mode 100644 Superposition/Tests.qs create mode 100644 quickref/qsharp-quick-reference.pdf create mode 100644 quickref/qsharp-quick-reference.tex diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..766b88338de --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto +*.sh text eol=lf + diff --git a/.gitignore b/.gitignore index 3e759b75bf4..bce367f11c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,330 +1,281 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -**/Properties/launchSettings.json - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_i.h -*.ilk -*.meta +# Git ignore file for the Solid project + +# Build artifacts +bin/ +obj/ +Documentation/Help/ +packages/ +src/simulation/Runtime/x64/ *.obj -*.iobj -*.pch +*.dll *.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc +*.exe +*.chm +*.html +Tests/build + +# test outputs +TestResults/ +*.qxe + +# Random VS files +*.suo *.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages +*.vspscc +UpgradeLog.htm +.vs +*.user + +# Random non-solution files +*.user *.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ +StyleCop.Cache +*.sublime-workspace +build_log.txt +.DS_store + +# Q# code-behind files: +*.g.cs + +## Core latex/pdflatex auxiliary files: +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.fmt +*.fot +*.cb +*.cb2 +.*.lb + +## Intermediate documents: +*.dvi +*.xdv +*-converted-to.* +# these rules might exclude image files for figures etc. +# *.ps +# *.eps + +## Generated if empty string is given at "Please type another file name for output:" +.pdf + +## Bibliography auxiliary files (bibtex/biblatex/biber): +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.run.xml + +## Build tool auxiliary files: +*.fdb_latexmk +*.synctex +*.synctex(busy) +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync + +## Build tool directories for auxiliary files +# latexrun +latex.out/ + +## Auxiliary and intermediate files from other packages: +# algorithms +*.alg +*.loa + +# achemso +acs-*.bib + +# amsthm +*.thm + +# beamer +*.nav +*.pre +*.snm +*.vrb + +# changes +*.soc + +# cprotect +*.cpt + +# elsarticle (documentclass of Elsevier journals) +*.spl + +# endnotes +*.ent + +# fixme +*.lox + +# feynmf/feynmp +*.mf +*.mp +*.t[1-9] +*.t[1-9][0-9] +*.tfm + +#(r)(e)ledmac/(r)(e)ledpar +*.end +*.?end +*.[1-9] +*.[1-9][0-9] +*.[1-9][0-9][0-9] +*.[1-9]R +*.[1-9][0-9]R +*.[1-9][0-9][0-9]R +*.eledsec[1-9] +*.eledsec[1-9]R +*.eledsec[1-9][0-9] +*.eledsec[1-9][0-9]R +*.eledsec[1-9][0-9][0-9] +*.eledsec[1-9][0-9][0-9]R + +# glossaries +*.acn +*.acr +*.glg +*.glo +*.gls +*.glsdefs + +# gnuplottex +*-gnuplottex-* + +# gregoriotex +*.gaux +*.gtex + +# htlatex +*.4ct +*.4tc +*.idv +*.lg +*.trc +*.xref + +# hyperref +*.brf + +# knitr +*-concordance.tex +# TODO Comment the next line if you want to keep your tikz graphics files +*.tikz +*-tikzDictionary + +# listings +*.lol + +# makeidx +*.idx +*.ilg +*.ind +*.ist + +# minitoc +*.maf +*.mlf +*.mlt +*.mtc[0-9]* +*.slf[0-9]* +*.slt[0-9]* +*.stc[0-9]* + +# minted +_minted* +*.pyg + +# morewrites +*.mw + +# nomencl +*.nlg +*.nlo +*.nls + +# pax +*.pax + +# pdfpcnotes +*.pdfpc + +# sagetex +*.sagetex.sage +*.sagetex.py +*.sagetex.scmd + +# scrwfile +*.wrt + +# sympy +*.sout +*.sympy +sympy-plots-for-*.tex/ + +# pdfcomment +*.upa +*.upb + +# pythontex +*.pytxcode +pythontex-files-*/ + +# thmtools +*.loe + +# TikZ & PGF +*.dpth +*.md5 +*.auxlock + +# todonotes +*.tdo + +# easy-todo +*.lod + +# xmpincl +*.xmpi + +# xindy +*.xdy + +# xypic precompiled matrices +*.xyc + +# endfloat +*.ttt +*.fff + +# Latexian +TSWLatexianTemp* + +## Editors: +# WinEdt +*.bak +*.sav + +# Texpad +.texpadtmp + +# Kile +*.backup + +# KBibTeX +*~[0-9]* -# MSBuild Binary and Structured Log -*.binlog +# auto folder when using emacs and auctex +./auto/* +*.el -# NVidia Nsight GPU debugger configuration file -*.nvuser +# expex forward references with \gathertags +*-tags.tex -# MFractors (Xamarin productivity tool) working folder -.mfractor/ +# standalone packages +*.sta diff --git a/BasicGates/.vscode/extensions.json b/BasicGates/.vscode/extensions.json new file mode 100644 index 00000000000..14d152e069a --- /dev/null +++ b/BasicGates/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "quantum.quantum-devkit-vscode" + ] +} \ No newline at end of file diff --git a/BasicGates/.vscode/tasks.json b/BasicGates/.vscode/tasks.json new file mode 100644 index 00000000000..bae788317e9 --- /dev/null +++ b/BasicGates/.vscode/tasks.json @@ -0,0 +1,36 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "args": [ + "build" + ], + "type": "process", + "group": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + }, + { + "label": "test", + "command": "dotnet", + "args": [ + "test" + ], + "type": "process", + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/BasicGates/BasicGates.csproj b/BasicGates/BasicGates.csproj new file mode 100644 index 00000000000..9035bc552c2 --- /dev/null +++ b/BasicGates/BasicGates.csproj @@ -0,0 +1,22 @@ + + + netcoreapp2.0 + x64 + false + Quantum.Kata.BasicGates + + + + + + + + + + + + + + + + diff --git a/BasicGates/BasicGates.sln b/BasicGates/BasicGates.sln new file mode 100644 index 00000000000..af20280bffa --- /dev/null +++ b/BasicGates/BasicGates.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicGates", "BasicGates.csproj", "{4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BAAB76A-ABFA-4F5C-9E5B-788BB3E8647E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7CB0806C-1BBF-4E0C-BDFC-04A9A068F41C} + EndGlobalSection +EndGlobal diff --git a/BasicGates/README.md b/BasicGates/README.md new file mode 100644 index 00000000000..9994a868864 --- /dev/null +++ b/BasicGates/README.md @@ -0,0 +1,14 @@ +# Welcome! + +The basic gates kata covers the basic operations (a.k.a. "gates") used in quantum computing, as well as the concept of controlled and adjoint versions of gates. + +#### Theory + +* A list of most common gates can be found in [this Wikipedia article](https://en.wikipedia.org/wiki/Quantum_logic_gate). +* [Quirk](http://algassert.com/quirk) is a convenient tool for visualizing the effect of gates on qubit states. + +#### Q# materials + +* Basic gates provided in Q# belong to the `Microsoft.Quantum.Primitive` namespace and are listed [here](https://docs.microsoft.com/qsharp/api/prelude/microsoft.quantum.primitive). +* Using controlled and adjoint versions of gates is covered in the Q# documentation on [operation types](https://docs.microsoft.com/en-us/quantum/quantum-qr-typemodel#operation-and-function-types). +* Defining controlled and adjoint versions of gates is covered in the Q# documentation on [operation definitions](https://docs.microsoft.com/en-us/quantum/quantum-qr-filestructure#operation-definitions). \ No newline at end of file diff --git a/BasicGates/ReferenceImplementation.qs b/BasicGates/ReferenceImplementation.qs new file mode 100644 index 00000000000..de87de43cdb --- /dev/null +++ b/BasicGates/ReferenceImplementation.qs @@ -0,0 +1,233 @@ +// 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.BasicGates +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + + ////////////////////////////////////////////////////////////////// + // Part I. Single-Qubit Gates + ////////////////////////////////////////////////////////////////// + + // Task 1.1. State flip + // Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩. + // Goal: Change the state of the qubit to α |1⟩ + β |0⟩. + // Example: + // If the qubit is in state |0〉, change its state to |1〉. + // If the qubit is in state |1〉, change its state to |0〉. + operation StateFlip_Reference (q : Qubit) : () + { + body + { + X(q); + } + adjoint self; + } + + // Task 1.2. Basis change: |0⟩ to |+⟩ and |1⟩ to |-⟩ (and vice versa) + // Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩. + // Goal: Change the state of the qubit as follows: + // If the qubit is in state |0〉, change its state to |+〉 = (|0⟩ + |1⟩) / sqrt(2). + // If the qubit is in state |1〉, change its state to |-〉 = (|0⟩ - |1⟩) / sqrt(2). + // If the qubit is in superposition, change its state according to the effect on basis vectors. + // Note: |+〉 and |-〉 form a different basis for single-qubit states, called X basis. + operation BasisChange_Reference (q : Qubit) : () + { + body + { + H(q); + } + adjoint self; + } + + // Task 1.3. Sign flip: |+〉 to |-〉 and vice versa. + // Inputs: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩. + // Goal: Change the qubit state to α |0⟩ - β |1⟩ (flip the sign of |1⟩ component of the superposition). + operation SignFlip_Reference (q : Qubit) : () + { + body + { + Z(q); + } + adjoint self; + } + + // Task 1.4*. Amplitude change (|0⟩ to cos(alpha)*|0〉 + sin(alpha)*|1〉). + // Inputs: + // 1) A qubit in state β|0⟩ + γ|1⟩. + // 2) Angle alpha, in radians, represented as Double + // Goal: Change the state of the qubit as follows: + // 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) : () + { + body + { + Ry(2.0 * alpha, q); + } + adjoint auto; + } + + // 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) : () + { + body + { + S(q); + // alternatively Rz(0.5 * PI(), q); + } + adjoint auto; + } + + // Task 1.6*. Phase change + // Inputs: + // 1) A qubit in state β|0⟩ + γ|1⟩. + // 2) Angle alpha, in radians, represented as Double + // Goal: Change the state of the qubit as follows: + // 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) : () + { + body + { + Rz(alpha, q); + } + adjoint auto; + } + + // 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[]) : () + { + body + { + Z(qs[0]); + // alternatively Z(qs[1]); + } + adjoint auto; + } + + // 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[]) : () + { + body + { + X(qs[0]); + // alternatively X(qs[1]); + } + adjoint auto; + } + + // 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[]) : () + { + body + { + Y(qs[0]); + } + adjoint auto; + } + + + ////////////////////////////////////////////////////////////////// + // Part II. Multi-Qubit Gates + ////////////////////////////////////////////////////////////////// + + // Task 2.1. Two-qubit gate - 1 + // Input: Two unentangled qubits (stored in an array of length 2). + // The first qubit will be in state |ψ⟩ = α |0⟩ + β |1⟩, the second - in state |0〉 + // (this can be written as two-qubit state (α|0⟩ + β|1⟩) ⊕ |0〉). + // Goal: Change the two-qubit state to α |00⟩ + β |11⟩. + // Note that unless the starting state of the first qubit was |0〉 or |1〉, + // the resulting two-qubit state can not be represented as a tensor product + // of the states of individual qubits any longer; thus the qubits become entangled. + operation TwoQubitGate1_Reference (qs : Qubit[]) : () + { + body + { + CNOT(qs[0], qs[1]); + } + adjoint self; + } + + // Task 2.2. Two-qubit gate - 2 + // Input: Two qubits (stored in an array of length 2) + // in state |+⟩ ⊕ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2. + // Goal: Change the two-qubit state to (|00⟩ + |01⟩ + |10⟩ - |11⟩) / 2. + // Note that while the starting state can be represented as a tensor product of single-qubit states, + // the resulting two-qubit state can not be represented in such a way. + operation TwoQubitGate2_Reference (qs : Qubit[]) : () + { + body + { + (Controlled Z)([qs[0]], qs[1]); + } + adjoint self; + } + + // Task 2.3. Two-qubit gate - 3 + // Input: Two qubits (stored in an array of length 2) in an arbitrary + // two-qubit state α|00⟩ + β|01⟩ + γ|10⟩ + δ|11⟩. + // Goal: Change the two-qubit state to α|00⟩ + γ|01⟩ + β|10⟩ + δ|11⟩. + operation TwoQubitGate3_Reference (qs : Qubit[]) : () + { + body + { + // Hint: this task can be solved using one primitive gate; + // as an exercise, try to express the solution using several controlled Pauli gates. + + CNOT(qs[0], qs[1]); + CNOT(qs[1], qs[0]); + CNOT(qs[0], qs[1]); + } + adjoint self; + } + + // Task 2.4. Toffoli gate + // Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩. + // Goal: Flip the state of the third qubit if the state of the first two is |11⟩: + // i.e., change the three-qubit state to + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + θ|110⟩ + η|111⟩. + operation ToffoliGate_Reference (qs : Qubit[]) : () + { + body + { + CCNOT(qs[0], qs[1], qs[2]); + // alternatively (Controlled X)(qs[0..1], qs[2]); + } + adjoint self; + } + + // Task 2.5. Fredkin gate + // Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩. + // Goal: Swap the states of second and third qubit if and only if the state of the first qubit is |1⟩: + // i.e., change the three-qubit state to + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + η|101⟩ + ζ|110⟩ + θ|111⟩. + operation FredkinGate_Reference (qs : Qubit[]) : () + { + body + { + (Controlled SWAP)([qs[0]], (qs[1], qs[2])); + } + adjoint self; + } +} diff --git a/BasicGates/Tasks.qs b/BasicGates/Tasks.qs new file mode 100644 index 00000000000..1f02dc7e483 --- /dev/null +++ b/BasicGates/Tasks.qs @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Quantum.Kata.BasicGates +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + + ////////////////////////////////////////////////////////////////// + // Welcome! + ////////////////////////////////////////////////////////////////// + + // "Basic Gates" quantum kata is a series of exercises designed + // to get you familiar with the basic quantum gates in Q#. + // It covers the following topics: + // - basic single-qubit and multi-qubit gates, + // - adjoint and controlled gates, + // - using gates to modify the state of a qubit. + // + // 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. + // + // Most tasks can be done using exactly one gate. + // None of the tasks require measurement, and the tests are written so as to fail if qubit state is measured. + // + // The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks. + + + ////////////////////////////////////////////////////////////////// + // Part I. Single-Qubit Gates + ////////////////////////////////////////////////////////////////// + + // Task 1.1. State flip: |0⟩ to |1⟩ and vice versa + // Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩. + // Goal: Change the state of the qubit to α |1⟩ + β |0⟩. + // Example: + // If the qubit is in state |0〉, change its state to |1〉. + // If the qubit is in state |1〉, change its state to |0〉. + // Note that this operation is self-adjoint: applying it for a second time + // returns the qubit to the original state. + operation StateFlip (q : Qubit) : () + { + body + { + // The Pauli X gate will change the |0〉 state to the |1〉 state and vice versa. + // Type X(q); + // Then rebuild the project and rerun the tests - T11_StateFlip_Test should now pass! + + // ... + } + adjoint self; + } + + // Task 1.2. Basis change: |0⟩ to |+⟩ and |1⟩ to |-⟩ (and vice versa) + // Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩. + // Goal: Change the state of the qubit as follows: + // If the qubit is in state |0〉, change its state to |+〉 = (|0⟩ + |1⟩) / sqrt(2). + // If the qubit is in state |1〉, change its state to |-〉 = (|0⟩ - |1⟩) / sqrt(2). + // If the qubit is in superposition, change its state according to the effect on basis vectors. + // Note: |+〉 and |-〉 form a different basis for single-qubit states, called X basis. + // |0〉 and |1〉 are called Z basis. + operation BasisChange (q : Qubit) : () + { + body + { + // ... + } + adjoint self; + } + + // Task 1.3. Sign flip: |+〉 to |-〉 and vice versa. + // Input: A qubit in state |ψ⟩ = α |0⟩ + β |1⟩. + // Goal: Change the qubit state to α |0⟩ - β |1⟩ (flip the sign of |1⟩ component of the superposition). + operation SignFlip (q : Qubit) : () + { + body + { + // ... + } + adjoint self; + } + + // Task 1.4*. Amplitude change: |0⟩ to cos(alpha)*|0〉 + sin(alpha)*|1〉. + // Inputs: + // 1) A qubit in state β|0⟩ + γ|1⟩. + // 2) Angle alpha, in radians, represented as Double + // Goal: Change the state of the qubit as follows: + // 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) : () + { + body + { + // ... + } + adjoint auto; + } + + // 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) : () + { + body + { + // ... + } + adjoint auto; + } + + // Task 1.6*. Phase change + // Inputs: + // 1) A qubit in state β|0⟩ + γ|1⟩. + // 2) Angle alpha, in radians, represented as Double + // Goal: Change the state of the qubit as follows: + // 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) : () + { + body + { + // ... + } + adjoint auto; + } + + // 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[]) : () + { + body + { + // ... + } + adjoint auto; + } + + // 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[]) : () + { + body + { + // ... + } + adjoint auto; + } + + // 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[]) : () + { + body + { + // ... + } + adjoint auto; + } + + + ////////////////////////////////////////////////////////////////// + // Part II. Multi-Qubit Gates + ////////////////////////////////////////////////////////////////// + + // Task 2.1. Two-qubit gate - 1 + // Input: Two unentangled qubits (stored in an array of length 2). + // The first qubit will be in state |ψ⟩ = α |0⟩ + β |1⟩, the second - in state |0〉 + // (this can be written as two-qubit state (α|0⟩ + β|1⟩) ⊕ |0〉). + // Goal: Change the two-qubit state to α |00⟩ + β |11⟩. + // Note that unless the starting state of the first qubit was |0〉 or |1〉, + // the resulting two-qubit state can not be represented as a tensor product + // of the states of individual qubits any longer; thus the qubits become entangled. + operation TwoQubitGate1 (qs : Qubit[]) : () + { + body + { + // ... + } + adjoint self; + } + + // Task 2.2. Two-qubit gate - 2 + // Input: Two qubits (stored in an array of length 2) + // in state |+⟩ ⊕ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2. + // Goal: Change the two-qubit state to (|00⟩ + |01⟩ + |10⟩ - |11⟩) / 2. + // Note that while the starting state can be represented as a tensor product of single-qubit states, + // the resulting two-qubit state can not be represented in such a way. + operation TwoQubitGate2 (qs : Qubit[]) : () + { + body + { + // ... + } + adjoint self; + } + + // Task 2.3. Two-qubit gate - 3 + // Input: Two qubits (stored in an array of length 2) in an arbitrary + // two-qubit state α|00⟩ + β|01⟩ + γ|10⟩ + δ|11⟩. + // Goal: Change the two-qubit state to α|00⟩ + γ|01⟩ + β|10⟩ + δ|11⟩. + operation TwoQubitGate3 (qs : Qubit[]) : () + { + body + { + // Hint: this task can be solved using one primitive gate; + // as an exercise, try to express the solution using several + // (possibly controlled) Pauli gates. + + // ... + } + adjoint self; + } + + // Task 2.4. Toffoli gate + // Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩. + // Goal: Flip the state of the third qubit if the state of the first two is |11⟩: + // i.e., change the three-qubit state to + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + θ|110⟩ + η|111⟩. + operation ToffoliGate (qs : Qubit[]) : () + { + body + { + // ... + } + adjoint self; + } + + // Task 2.5. Fredkin gate + // Input: Three qubits (stored in an array of length 3) in an arbitrary three-qubit state + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + ζ|101⟩ + η|110⟩ + θ|111⟩. + // Goal: Swap the states of second and third qubit if and only if the state of the first qubit is |1⟩: + // α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ε|100⟩ + η|101⟩ + ζ|110⟩ + θ|111⟩. + operation FredkinGate (qs : Qubit[]) : () + { + body + { + // ... + } + adjoint self; + } +} diff --git a/BasicGates/TestSuiteRunner.cs b/BasicGates/TestSuiteRunner.cs new file mode 100644 index 00000000000..225b4222376 --- /dev/null +++ b/BasicGates/TestSuiteRunner.cs @@ -0,0 +1,42 @@ +// 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 Microsoft.Quantum.Simulation.Simulators; +using Xunit.Abstractions; +using System.Diagnostics; + +namespace Quantum.Kata.BasicGates +{ + public class TestSuiteRunner + { + private readonly ITestOutputHelper output; + + public TestSuiteRunner(ITestOutputHelper output) + { + this.output = output; + } + + /// + /// This driver will run all Q# tests (operations named "...Test") + /// that belong to namespace Quantum.Kata.BasicGates. + /// + [OperationDriver(TestNamespace = "Quantum.Kata.BasicGates")] + public void TestTarget(TestOperation op) + { + using (var sim = new QuantumSimulator()) + { + // 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); + } + } + } +} diff --git a/BasicGates/Tests.qs b/BasicGates/Tests.qs new file mode 100644 index 00000000000..8228b443ed7 --- /dev/null +++ b/BasicGates/Tests.qs @@ -0,0 +1,268 @@ +// 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.BasicGates +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Convert; + open Microsoft.Quantum.Extensions.Math; + open Microsoft.Quantum.Extensions.Testing; + + // ------------------------------------------------------ + // helper wrapper to represent operation on one qubit as an operation on an array of qubits + operation ArrayWrapperOperation (op : ((Qubit) => () : Adjoint), qs : Qubit[]) : () + { + body + { + op(qs[0]); + } + adjoint + { + (Adjoint op)(qs[0]); + } + } + + // ------------------------------------------------------ + operation T11_StateFlip_Test () : () + { + body + { + AssertOperationsEqualReferenced(ArrayWrapperOperation(StateFlip, _), ArrayWrapperOperation(StateFlip_Reference, _), 1); + } + } + + // ------------------------------------------------------ + operation T12_BasisChange_Test () : () + { + body + { + AssertOperationsEqualReferenced(ArrayWrapperOperation(BasisChange, _), ArrayWrapperOperation(BasisChange_Reference, _), 1); + } + } + + // ------------------------------------------------------ + operation T13_SignFlip_Test () : () + { + body + { + AssertOperationsEqualReferenced(ArrayWrapperOperation(SignFlip, _), ArrayWrapperOperation(SignFlip_Reference, _), 1); + } + } + + // ------------------------------------------------------ + operation T14_AmplitudeChange_Test () : () + { + body + { + for (i in 0..36) { + let alpha = 2.0 * PI() * ToDouble(i) / 36.0; + AssertOperationsEqualReferenced(ArrayWrapperOperation(AmplitudeChange(_, alpha), _), ArrayWrapperOperation(AmplitudeChange_Reference(_, alpha), _), 1); + } + } + } + + // ------------------------------------------------------ + operation T15_PhaseFlip_Test () : () + { + body + { + AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseFlip, _), ArrayWrapperOperation(PhaseFlip_Reference, _), 1); + } + } + + // ------------------------------------------------------ + operation T16_PhaseChange_Test () : () + { + body + { + for (i in 0..36) { + let alpha = 2.0 * PI() * ToDouble(i) / 36.0; + AssertOperationsEqualReferenced(ArrayWrapperOperation(PhaseChange(_, alpha), _), ArrayWrapperOperation(PhaseChange_Reference(_, alpha), _), 1); + } + } + } + + // ------------------------------------------------------ + // 0 - |Φ⁺〉 = (|00〉 + |11〉) / sqrt(2) + // 1 - |Φ⁻〉 = (|00〉 - |11〉) / sqrt(2) + // 2 - |Ψ⁺〉 = (|01〉 + |10〉) / sqrt(2) + // 3 - |Ψ⁻〉 = (|01〉 - |10〉) / sqrt(2) + operation StatePrep_BellState (qs : Qubit[], state : Int) : () { + body { + 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]); + } + } + adjoint auto; + } + + // ------------------------------------------------------ + operation VerifyBellStateConversion( + testOp : ((Qubit[]) => ()), + startState : Int, + targetState : Int) : () { + body { + using (qs = Qubit[2]) + { + // prepare Bell state startState + StatePrep_BellState(qs, startState); + + // apply operation that needs to be tested + testOp(qs); + + // verify the result by applying adjoint of state prep for target state + (Adjoint StatePrep_BellState)(qs, targetState); + + // assert that all qubits end up in |0〉 state + AssertAllZero(qs); + } + } + } + // ------------------------------------------------------ + operation T17_BellStateChange1_Test () : () + { + body + { + VerifyBellStateConversion(BellStateChange1, 0, 1); + } + } + + // ------------------------------------------------------ + operation T18_BellStateChange2_Test () : () + { + body + { + VerifyBellStateConversion(BellStateChange2, 0, 2); + } + } + + // ------------------------------------------------------ + operation T19_BellStateChange3_Test () : () + { + body + { + VerifyBellStateConversion(BellStateChange3, 0, 3); + } + } + + // ------------------------------------------------------ + // prepare state |A〉 = cos(α) * |0〉 + sin(α) * |1〉 + operation StatePrep_A (alpha : Double, q : Qubit) : () { + body { + Ry(2.0 * alpha, q); + } + adjoint auto; + } + + // ------------------------------------------------------ + operation T21_TwoQubitGate1_Test () : () + { + body + { + // Note that the way the problem is formulated, we can't just compare two unitaries, + // 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; + + // prepare A state + StatePrep_A(alpha, qs[0]); + + // apply operation that needs to be tested + TwoQubitGate1(qs); + + // apply adjoint reference operation and adjoint of state prep + (Adjoint TwoQubitGate1_Reference)(qs); + (Adjoint StatePrep_A)(alpha, qs[0]); + + // assert that all qubits end up in |0〉 state + AssertAllZero(qs); + } + } + } + } + + // ------------------------------------------------------ + // prepare state |+⟩ ⊕ |+⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩) / 2. + operation StatePrep_PlusPlus (qs : Qubit[]) : () { + body { + ApplyToEachA(H, qs); + } + adjoint auto; + } + + // ------------------------------------------------------ + operation T22_TwoQubitGate2_Test () : () + { + body + { + using (qs = Qubit[2]) + { + // prepare |+⟩ ⊕ |+⟩ state + StatePrep_PlusPlus(qs); + + // apply operation that needs to be tested + TwoQubitGate2(qs); + + // apply adjoint reference operation and adjoint of state prep + (Adjoint TwoQubitGate2_Reference)(qs); + (Adjoint StatePrep_PlusPlus)(qs); + + // assert that all qubits end up in |0〉 state + AssertAllZero(qs); + } + } + } + + // ------------------------------------------------------ + operation SwapWrapper (qs : Qubit[]) : () + { + body + { + SWAP(qs[0], qs[1]); + } + adjoint self; + } + + operation T23_TwoQubitGate3_Test () : () + { + body + { + AssertOperationsEqualReferenced(SwapWrapper, TwoQubitGate3_Reference, 2); + AssertOperationsEqualReferenced(TwoQubitGate3, TwoQubitGate3_Reference, 2); + } + } + + // ------------------------------------------------------ + operation T24_ToffoliGate_Test () : () + { + body + { + AssertOperationsEqualReferenced(ToffoliGate, ToffoliGate_Reference, 3); + } + } + + // ------------------------------------------------------ + operation T25_FredkinGate_Test () : () + { + body + { + AssertOperationsEqualReferenced(FredkinGate, FredkinGate_Reference, 3); + } + } +} \ No newline at end of file diff --git a/DeutschJozsaAlgorithm/.vscode/extensions.json b/DeutschJozsaAlgorithm/.vscode/extensions.json new file mode 100644 index 00000000000..14d152e069a --- /dev/null +++ b/DeutschJozsaAlgorithm/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "quantum.quantum-devkit-vscode" + ] +} \ No newline at end of file diff --git a/DeutschJozsaAlgorithm/.vscode/tasks.json b/DeutschJozsaAlgorithm/.vscode/tasks.json new file mode 100644 index 00000000000..bae788317e9 --- /dev/null +++ b/DeutschJozsaAlgorithm/.vscode/tasks.json @@ -0,0 +1,36 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "args": [ + "build" + ], + "type": "process", + "group": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + }, + { + "label": "test", + "command": "dotnet", + "args": [ + "test" + ], + "type": "process", + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.csproj b/DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.csproj new file mode 100644 index 00000000000..7c3e1ac9ed5 --- /dev/null +++ b/DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.csproj @@ -0,0 +1,22 @@ + + + netcoreapp2.0 + x64 + false + Quantum.Kata.DeutschJozsaAlgorithm + + + + + + + + + + + + + + + + diff --git a/DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.sln b/DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.sln new file mode 100644 index 00000000000..cbb31e50ad5 --- /dev/null +++ b/DeutschJozsaAlgorithm/DeutschJozsaAlgorithm.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeutschJozsaAlgorithm", "DeutschJozsaAlgorithm.csproj", "{B4477C91-FBD6-4DCE-8B4C-1A5E48669790}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4477C91-FBD6-4DCE-8B4C-1A5E48669790}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F23513ED-2103-49D7-9F64-7BA3199FC689} + EndGlobalSection +EndGlobal diff --git a/DeutschJozsaAlgorithm/OracleCounterSimulator.cs b/DeutschJozsaAlgorithm/OracleCounterSimulator.cs new file mode 100644 index 00000000000..02c2b5a7d5d --- /dev/null +++ b/DeutschJozsaAlgorithm/OracleCounterSimulator.cs @@ -0,0 +1,94 @@ +// 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 System; +using System.Collections.Generic; +using Microsoft.Quantum.Simulation.Core; +using Microsoft.Quantum.Simulation.Simulators; + +using Xunit; + +namespace Quantum.Kata.DeutschJozsaAlgorithm +{ + /// + /// This custom quantum simulator keeps track of the number of times + /// each operation is executed, by providing a custom native operation: + /// `AssertOracleCallsCount` which asserts the number of times + /// the given oracle (operation) has been called. + /// + public class OracleCounterSimulator : QuantumSimulator + { + private Dictionary _operationsCount = new Dictionary(); + + public OracleCounterSimulator( + bool throwOnReleasingQubitsNotInZeroState = true, + uint? randomNumberGeneratorSeed = null, + bool disableBorrowing = false) : + base(throwOnReleasingQubitsNotInZeroState, randomNumberGeneratorSeed, disableBorrowing) + { + this.OnOperationStart += CountOperationCalls; + } + + /// + /// Callback method for the OnOperationStart event. + /// + public void CountOperationCalls(ICallable op, IApplyData data) + { + if (_operationsCount.ContainsKey(op)) + { + _operationsCount[op]++; + } + else + { + _operationsCount[op] = 1; + } + } + + // Custom Native operation to reset the oracle counts back to 0. + public class ResetOracleCallsImpl : ResetOracleCallsCount + { + OracleCounterSimulator _sim; + + public ResetOracleCallsImpl(OracleCounterSimulator m) : base(m) + { + _sim = m; + } + + public override Func Body => (__in) => + { + _sim._operationsCount.Clear(); + return QVoid.Instance; + }; + } + + // Custom Native operation to Assert the number of calls for an Operation. + public class AssertOracleCallsImpl : AssertOracleCallsCount + { + OracleCounterSimulator _sim; + + public AssertOracleCallsImpl(OracleCounterSimulator m) : base(m) + { + _sim = m; + } + + public override Func<(Int64, T), QVoid> Body => (__in) => + { + var (expected, oracle) = __in; + + var op = oracle as ICallable; + Assert.NotNull(op); + + var actual = _sim._operationsCount.ContainsKey(op) ? _sim._operationsCount[op] : 0; + Assert.True(expected >= actual, $"Oracle should be called at most {expected} time(s), your solution called it {actual} time(s)."); + + return QVoid.Instance; + }; + } + } +} diff --git a/DeutschJozsaAlgorithm/README.md b/DeutschJozsaAlgorithm/README.md new file mode 100644 index 00000000000..5523e257c4c --- /dev/null +++ b/DeutschJozsaAlgorithm/README.md @@ -0,0 +1,15 @@ +# Welcome! + +This kata covers several well-studied algorithms and concepts. + +#### Deutsch-Jozsa algorithm +* A good place to start is [Wikipedia](https://en.wikipedia.org/wiki/Deutsch%E2%80%93Jozsa_algorithm). +* Nielsen, M. A. & Chuang, I. L. (2010). Quantum Computation and Quantum Information. pp. 34-36 +* [Lecture 5: A simple searching algorithm; the Deutsch-Jozsa algorithm](https://cs.uwaterloo.ca/~watrous/CPSC519/LectureNotes/05.pdf) + +#### Bernstein-Vazirani algorithm + +* Bernstein, E. & Vazirani, U. (1997). Quantum complexity theory. SIAM J. Comput. 26, 5, pp. 1411-1473. +* ["Quantum Algorithm Implementations for Beginners"](https://arxiv.org/pdf/1804.03719.pdf), section III. +* ["A Generalization of Bernstein-Vazirani Algorithm to Qudit Systems"](https://arxiv.org/pdf/1609.03185.pdf). + \ No newline at end of file diff --git a/DeutschJozsaAlgorithm/ReferenceImplementation.qs b/DeutschJozsaAlgorithm/ReferenceImplementation.qs new file mode 100644 index 00000000000..6e842a07fae --- /dev/null +++ b/DeutschJozsaAlgorithm/ReferenceImplementation.qs @@ -0,0 +1,373 @@ +// 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.DeutschJozsaAlgorithm +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + + ////////////////////////////////////////////////////////////////// + // Part I. Oracles + ////////////////////////////////////////////////////////////////// + + // Task 1.1. f(x) = 0 + // Inputs: + // 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) : () + { + 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 auto; + } + + // Task 1.2. f(x) = 1 + // Inputs: + // 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) : () + { + 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 auto; + } + + // Task 1.3. f(x) = xₖ (the value of k-th qubit) + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 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) : () + { + body + { + AssertBoolEqual(0 <= k && k < Length(x), true, "k should be between 0 and N-1, inclusive"); + CNOT(x[k], y); + } + adjoint auto; + } + + // Task 1.4. f(x) = 1 if x has odd number of 1s, and 0 otherwise + // Inputs: + // 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) : () + { + 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); + } + adjoint auto; + } + + // Task 1.5. f(x) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for a given bit vector r (scalar product function) + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 2) a qubit in arbitrary state |y〉 (output qubit) + // 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). + // + // 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[]) : () + { + 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"); + + for (i in 0..Length(x)-1) { + if (r[i] == 1) { + CNOT(x[i], y); + } + } + } + adjoint auto; + } + + // Task 1.6. f(x) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) modulo 2 for a given bit vector r + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 2) a qubit in arbitrary state |y〉 (output qubit) + // 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[]) : () + { + 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"); + + 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]); + } + } + } + adjoint auto; + } + + // Task 1.7. f(x) = Σᵢ 𝑥ᵢ + (1 if prefix of x is equal to the given bit vector, and 0 otherwise) modulo 2 + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 2) a qubit in arbitrary state |y〉 (output qubit) + // 3) a bit vector of length P represented as Int[] (1 <= P <= N) + // Goal: transform state |x, y〉 into state |x, y ⊕ f(x)〉 (⊕ is addition modulo 2). + // + // 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[]) : () + { + 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 && 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); + } + + // 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]); + } + } + } + adjoint auto; + } + + // Task 1.8*. f(x) = 1 if x has two or three bits (out of three) set to 1, and 0 otherwise (majority function) + // Inputs: + // 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) : () + { + 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"); + + // 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 auto; + } + + + ////////////////////////////////////////////////////////////////// + // Part II. Bernstein-Vazirani Algorithm + ////////////////////////////////////////////////////////////////// + + // Task 2.1. State preparation for Bernstein-Vazirani algorithm + // Inputs: + // 1) N qubits in |0〉 state (query register) + // 2) a qubit in |0〉 state (answer register) + // Goal: + // 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) : () + { + body + { + ApplyToEachA(H, query); + X(answer); + H(answer); + } + adjoint auto; + } + + // Task 2.2. Bernstein-Vazirani algorithm implementation + // Inputs: + // 1) the number of qubits in the input register N for the function f + // 2) a quantum operation which implements the oracle |x〉|y〉 -> |x〉|y ⊕ f(x)〉, where + // x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function + // You are guaranteed that the function f implemented by the oracle is a scalar product function + // (can be represented as f(𝑥₀, …, 𝑥ₙ₋₁) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for some bit vector r = (𝑟₀, …, 𝑟ₙ₋₁)). + // You have implemented the oracle implementing the scalar product function in task 1.5. + // Output: + // A bit vector r reconstructed from the function + // + // Note: a trivial approach is to call the oracle N times: + // |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) => ())) : Int[] + { + body + { + mutable r = new Int[N]; + + // allocate N+1 qubits + using (qs = Qubit[N+1]) { + // split allocated qubits into input register and answer register + let x = qs[0..N-1]; + let y = qs[N]; + + // prepare qubits in the right state + BV_StatePrep_Reference(x, y); + + // apply oracle + Uf(x, y); + + // apply Hadamard to each qubit of the input register + ApplyToEach(H, x); + + // measure all qubits of the input register; + // the result of each measurement is converted to a Bool + for (i in 0..N-1) { + if (M(x[i]) != Zero) { + set r[i] = 1; + } + } + + // before releasing the qubits make sure they are all in |0〉 state + ResetAll(qs); + } + return r; + } + } + + + ////////////////////////////////////////////////////////////////// + // Part III. Deutsch-Jozsa Algorithm + ////////////////////////////////////////////////////////////////// + + // Task 3.1. Deutsch-Jozsa algorithm implementation + // Inputs: + // 1) the number of qubits in the input register N for the function f + // 2) a quantum operation which implements the oracle |x〉|y〉 -> |x〉|y ⊕ f(x)〉, where + // x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function + // You are guaranteed that the function f implemented by the oracle is either + // constant (returns 0 on all inputs or 1 on all inputs) or + // balanced (returns 0 on exactly one half of the input domain and 1 on the other half). + // Output: + // true if the function f is constant + // false if the function f is balanced + // + // Note: a trivial approach is to call the oracle multiple times: + // if the values for more than half of the possible inputs are the same, the function is constant. + // Quantum computing allows to perform this task in just one call to the oracle; try to implement this algorithm. + operation DJ_Algorithm_Reference (N : Int, Uf : ((Qubit[], Qubit) => ())) : Bool + { + body + { + // Declare variable in which the result will be accumulated; + // this variable has to be mutable to allow updating it. + mutable isConstantFunction = true; + + // Hint: even though Deutsch-Jozsa algorithm operates on a wider class of functions + // than Bernstein-Vazirani (i.e. functions which can not be represented as a scalar product, such as f(x) = 1), + // it can be expressed as running Bernstein-Vazirani algorithm + // and then post-processing the return value classically: + // the function is constant if and only if all elements of the returned array are false + + let r = BV_Algorithm_Reference(N, Uf); + for (i in 0..N-1) { + set isConstantFunction = isConstantFunction && (r[i] == 0); + } + + return isConstantFunction; + } + } + + + ////////////////////////////////////////////////////////////////// + // Part IV. Come up with your own algorithm! + ////////////////////////////////////////////////////////////////// + + // Task 4.1. Reconstruct the oracle from task 1.6 + // Inputs: + // 1) the number of qubits in the input register N for the function f + // 2) a quantum operation which implements the oracle |x〉|y〉 -> |x〉|y ⊕ f(x)〉, where + // x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function + // You are guaranteed that the function f implemented by the oracle can be represented as + // f(𝑥₀, …, 𝑥ₙ₋₁) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) modulo 2 for some bit vector r = (𝑟₀, …, 𝑟ₙ₋₁). + // You have implemented the oracle implementing this function in task 1.6. + // 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) => ())) : Int[] + { + body + { + // 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 (qs = Qubit[N+1]) { + // split allocated qubits into input register and answer register + let x = qs[0..N-1]; + let y = qs[N]; + + // apply oracle to qubits in all 0 state + Uf(x, y); + + // f(x) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) = 2 Σᵢ 𝑟ᵢ 𝑥ᵢ + Σᵢ 𝑟ᵢ + Σᵢ 𝑥ᵢ + N = Σᵢ 𝑟ᵢ + N + // remove the N from the expression + if (N % 2 == 1) { + X(y); + } + + // now y = Σᵢ 𝑟ᵢ + + // measure the output register + let m = M(y); + if (m == One) { + // adjust parity of bit vector r + set r[0] = 1; + } + + // before releasing the qubits make sure they are all in |0〉 state + ResetAll(qs); + } + + return r; + } + } +} diff --git a/DeutschJozsaAlgorithm/Tasks.qs b/DeutschJozsaAlgorithm/Tasks.qs new file mode 100644 index 00000000000..0a374d48ca0 --- /dev/null +++ b/DeutschJozsaAlgorithm/Tasks.qs @@ -0,0 +1,351 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Quantum.Kata.DeutschJozsaAlgorithm +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + + ////////////////////////////////////////////////////////////////// + // Welcome! + ////////////////////////////////////////////////////////////////// + + // "Deutsch-Jozsa algorithm" quantum kata is a series of exercises designed + // to get you familiar with programming in Q#. + // It covers the following topics: + // - writing oracles (quantum operations which implement certain classical functions), + // - Bernstein-Vazirani algorithm for recovering the parameters of a scalar product function, + // - Deutsch-Jozsa algorithm for recognizing a function as constant or balanced, and + // - writing tests in Q#. + // + // 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. + + ////////////////////////////////////////////////////////////////// + // Part I. Oracles + ////////////////////////////////////////////////////////////////// + + // In this section you will implement oracles defined by classical functions using the following rules: + // - a function f(𝑥₀, …, 𝑥ₙ₋₁) with N bits of input x = (𝑥₀, …, 𝑥ₙ₋₁) and 1 bit of output y + // defines an oracle which acts on N input qubits and 1 output qubit. + // - the oracle effect on qubits in computational basis states is defined as follows: + // |x〉 |y〉 -> |x〉 |y ⊕ f(x)〉 (⊕ is addition modulo 2) + // - the oracle effect on qubits in superposition is defined following the linearity of quantum operations. + // - the oracle must act properly on qubits in all possible input states. + + // Task 1.1. f(x) = 0 + // Inputs: + // 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 (x : Qubit[], y : Qubit) : () + { + 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. + } + } + + // Task 1.2. f(x) = 1 + // Inputs: + // 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 (x : Qubit[], y : Qubit) : () + { + 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). + + // ... + } + } + + // Task 1.3. f(x) = xₖ (the value of k-th qubit) + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 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 (x : Qubit[], y : Qubit, k : Int) : () + { + body + { + // 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 && k < Length(x), true, "k should be between 0 and N-1, inclusive"); + + // ... + } + } + + // Task 1.4. f(x) = 1 if x has odd number of 1s, and 0 otherwise + // Inputs: + // 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 (x : Qubit[], y : Qubit) : () + { + body + { + // Hint: f(x) can be represented as x_0 ⊕ x_1 ⊕ ... ⊕ x_(N-1) + + // ... + } + } + + // Task 1.5. f(x) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for a given bit vector r (scalar product function) + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 2) a qubit in arbitrary state |y〉 (output qubit) + // 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). + // + // Note: the functions featured in tasks 1.1, 1.3 and 1.4 are special cases of this function. + operation Oracle_ProductFunction (x : Qubit[], y : Qubit, r : Int[]) : () + { + 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"); + + // ... + } + } + + // Task 1.6. f(x) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) modulo 2 for a given bit vector r + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 2) a qubit in arbitrary state |y〉 (output qubit) + // 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 (x : Qubit[], y : Qubit, r : Int[]) : () + { + 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"); + + // ... + } + } + + // Task 1.7. f(x) = Σᵢ 𝑥ᵢ + (1 if prefix of x is equal to the given bit vector, and 0 otherwise) modulo 2 + // Inputs: + // 1) N qubits in arbitrary state |x〉 (input register) + // 2) a qubit in arbitrary state |y〉 (output qubit) + // 3) a bit vector of length P represented as Int[] (1 <= P <= N) + // Goal: transform state |x, y〉 into state |x, y ⊕ f(x)〉 (⊕ is addition modulo 2). + // + // 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 (x : Qubit[], y : Qubit, prefix : Int[]) : () + { + 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 && 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 + + // ... + + // Hint: you can use Controlled functor to perform multicontrolled gates + // (gates with multiple control qubits). + + // ... + } + } + + // Task 1.8*. f(x) = 1 if x has two or three bits (out of three) set to 1, and 0 otherwise (majority function) + // Inputs: + // 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 (x : Qubit[], y : Qubit) : () + { + 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"); + + // Hint: represent f(x) in terms of AND and ⊕ operations + + // ... + } + } + + + ////////////////////////////////////////////////////////////////// + // Part II. Bernstein-Vazirani Algorithm + ////////////////////////////////////////////////////////////////// + + // Task 2.1. State preparation for Bernstein-Vazirani algorithm + // Inputs: + // 1) N qubits in |0〉 state (query register) + // 2) a qubit in |0〉 state (answer register) + // Goal: + // 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) : () + { + body + { + // ... + } + adjoint auto; + } + + // Task 2.2. Bernstein-Vazirani algorithm implementation + // Inputs: + // 1) the number of qubits in the input register N for the function f + // 2) a quantum operation which implements the oracle |x〉|y〉 -> |x〉|y ⊕ f(x)〉, where + // x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function + // You are guaranteed that the function f implemented by the oracle is a scalar product function + // (can be represented as f(𝑥₀, …, 𝑥ₙ₋₁) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for some bit vector r = (𝑟₀, …, 𝑟ₙ₋₁)). + // You have implemented the oracle implementing the scalar product function in task 1.5. + // Output: + // A bit vector r reconstructed from the function + // + // Note: a trivial approach is to call the oracle N times: + // |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 (N : Int, Uf : ((Qubit[], Qubit) => ())) : Int[] + { + body + { + // 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]; + + // ... + + return r; + } + } + + // Task 2.3. Testing Bernstein-Vazirani algorithm + // Goal: use your implementation of Bernstein-Vazirani algorithm from task 2.2 to figure out + // what bit vector the scalar product function oracle from task 1.5 was using. + // As a reminder, this oracle creates an operation f(x) = Σᵢ 𝑟ᵢ 𝑥ᵢ modulo 2 for a given bit vector r, + // and Bernstein-Vazirani algorithm recovers that bit vector given the operation. + operation BV_Test () : () + { + body + { + // Hint: use Oracle_ProductFunction to implement the scalar product function oracle passed to BV_Algorithm. + // Since Oracle_ProductFunction takes three arguments (Qubit[], Qubit and Int[]), + // and the operation passed to BV_Algorithm must take two arguments (Qubit[] and Qubit), + // you need to use partial application to fix the third argument (a specific value of a bit vector). + // + // 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 + // 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. + + // ... + } + } + + + ////////////////////////////////////////////////////////////////// + // Part III. Deutsch-Jozsa Algorithm + ////////////////////////////////////////////////////////////////// + + // Task 3.1. Deutsch-Jozsa algorithm implementation + // Inputs: + // 1) the number of qubits in the input register N for the function f + // 2) a quantum operation which implements the oracle |x〉|y〉 -> |x〉|y ⊕ f(x)〉, where + // x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function + // You are guaranteed that the function f implemented by the oracle is either + // constant (returns 0 on all inputs or 1 on all inputs) or + // balanced (returns 0 on exactly one half of the input domain and 1 on the other half). + // Output: + // true if the function f is constant + // false if the function f is balanced + // + // Note: a trivial approach is to call the oracle multiple times: + // if the values for more than half of the possible inputs are the same, the function is constant. + // Quantum computing allows to perform this task in just one call to the oracle; try to implement this algorithm. + operation DJ_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => ())) : Bool + { + body + { + // Declare Bool variable in which the result will be accumulated; + // this variable has to be mutable to allow updating it. + mutable isConstantFunction = true; + + // Hint: even though Deutsch-Jozsa algorithm operates on a wider class of functions + // than Bernstein-Vazirani (i.e. functions which can not be represented as a scalar product, such as f(x) = 1), + // it can be expressed as running Bernstein-Vazirani algorithm + // and then post-processing the return value classically + + // ... + + return isConstantFunction; + } + } + + // Task 3.2. Testing Deutsch-Jozsa algorithm + // Goal: use your implementation of Deutsch-Jozsa algorithm from task 3.1 to test + // each of the oracles you've implemented in part I for being constant or balanced. + operation DJ_Test () : () + { + body + { + // Hint: you will need to use partial application to test Oracle_Kth_Qubit and Oracle_ParityFunction; + // 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 + + // DJ_Test appears in the list of unit tests for the solution; run it to verify your code. + + // ... + } + } + + + ////////////////////////////////////////////////////////////////// + // Part IV. Come up with your own algorithm! + ////////////////////////////////////////////////////////////////// + + // Task 4.1. Reconstruct the oracle from task 1.6 + // Inputs: + // 1) the number of qubits in the input register N for the function f + // 2) a quantum operation which implements the oracle |x〉|y〉 -> |x〉|y ⊕ f(x)〉, where + // x is N-qubit input register, y is 1-qubit answer register, and f is a Boolean function + // You are guaranteed that the function f implemented by the oracle can be represented as + // f(𝑥₀, …, 𝑥ₙ₋₁) = Σᵢ (𝑟ᵢ 𝑥ᵢ + (1 - 𝑟ᵢ)(1 - 𝑥ᵢ)) modulo 2 for some bit vector r = (𝑟₀, …, 𝑟ₙ₋₁). + // You have implemented the oracle implementing this function in task 1.6. + // Output: + // A bit vector r which generates the same oracle as the one you are given + operation Noname_Algorithm (N : Int, Uf : ((Qubit[], Qubit) => ())) : Int[] + { + body + { + // 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]; + + // ... + + return r; + } + } +} diff --git a/DeutschJozsaAlgorithm/TestSuiteRunner.cs b/DeutschJozsaAlgorithm/TestSuiteRunner.cs new file mode 100644 index 00000000000..2eed269d5bb --- /dev/null +++ b/DeutschJozsaAlgorithm/TestSuiteRunner.cs @@ -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 System.Diagnostics; + +using Microsoft.Quantum.Simulation.XUnit; +using Xunit.Abstractions; + + +namespace Quantum.Kata.DeutschJozsaAlgorithm +{ + public class TestSuiteRunner + { + private readonly ITestOutputHelper output; + + public TestSuiteRunner(ITestOutputHelper output) + { + this.output = output; + } + + /// + /// This driver will run all Q# tests (operations named "...Test") + /// that belong to namespace Quantum.Kata.DeutschJozsaAlgorithm. + /// + [OperationDriver(TestNamespace = "Quantum.Kata.DeutschJozsaAlgorithm")] + public void TestTarget(TestOperation op) + { + using (var sim = new OracleCounterSimulator()) + { + // 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); + } + } + } +} diff --git a/DeutschJozsaAlgorithm/Tests.qs b/DeutschJozsaAlgorithm/Tests.qs new file mode 100644 index 00000000000..2c26e834a0a --- /dev/null +++ b/DeutschJozsaAlgorithm/Tests.qs @@ -0,0 +1,348 @@ +// 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.DeutschJozsaAlgorithm +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Testing; + + // ------------------------------------------------------ + operation ApplyOracle (qs : Qubit[], oracle : ((Qubit[], Qubit) => ())) : () + { + body + { + let N = Length(qs); + oracle(qs[0..N-2], qs[N-1]); + } + } + + // ------------------------------------------------------ + operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => () : Adjoint)) : () + { + body + { + let N = Length(qs); + oracle(qs[0..N-2], qs[N-1]); + } + adjoint auto; + } + + // ------------------------------------------------------ + operation AssertTwoOraclesAreEqual (nQubits : Range, + oracle1 : ((Qubit[], Qubit) => ()), + oracle2 : ((Qubit[], Qubit) => () : Adjoint)) : () + { + body + { + let sol = ApplyOracle(_, oracle1); + let refSol = ApplyOracleA(_, oracle2); + for (i in nQubits) { + AssertOperationsEqualReferenced(sol, refSol, i+1); + } + } + } + + // ------------------------------------------------------ + operation T11_Oracle_Zero_Test () : () + { + body + { + AssertTwoOraclesAreEqual(1..10, Oracle_Zero, Oracle_Zero_Reference); + } + } + + // ------------------------------------------------------ + operation T12_Oracle_One_Test () : () + { + body + { + AssertTwoOraclesAreEqual(1..10, Oracle_One, Oracle_One_Reference); + } + } + + // ------------------------------------------------------ + operation T13_Oracle_Kth_Qubit_Test () : () + { + body + { + let maxQ = 6; + // loop over index of the qubit to be used + for (k in 0..maxQ-1) { + // number of qubits to try is from k+1 to 6 + AssertTwoOraclesAreEqual(k+1..maxQ, Oracle_Kth_Qubit(_, _, k), Oracle_Kth_Qubit_Reference(_, _, k)); + } + } + } + + // ------------------------------------------------------ + operation T14_Oracle_OddNumberOfOnes_Test () : () + { + body + { + // cross-test: for 1 qubit it's the same as Kth_Qubit for k = 0 + AssertTwoOraclesAreEqual(1..1, Oracle_OddNumberOfOnes, Oracle_Kth_Qubit_Reference(_, _, 0)); + + AssertTwoOraclesAreEqual(1..10, Oracle_OddNumberOfOnes, Oracle_OddNumberOfOnes_Reference); + } + } + + // ------------------------------------------------------ + operation AssertTwoOraclesWithIntAreEqual (r : Int[], + oracle1 : ((Qubit[], Qubit, Int[]) => ()), + oracle2 : ((Qubit[], Qubit, Int[]) => () : Adjoint)) : () + { + body + { + AssertTwoOraclesAreEqual(Length(r)..Length(r), oracle1(_, _, r), oracle2(_, _, r)); + } + } + + operation T15_Oracle_ProductFunction_Test () : () + { + body + { + // cross-tests + // the mask for all 1's corresponds to Oracle_OddNumberOfOnes + mutable r = [1; 1; 1; 1; 1; 1; 1; 1; 1; 1]; + let L = Length(r); + for (i in 2..L) { + AssertTwoOraclesAreEqual(i..i, Oracle_ProductFunction(_, _, r[0..i-1]), Oracle_OddNumberOfOnes_Reference); + } + + // the mask with all 0's corresponds to Oracle_Zero + for (i in 0..L-1) { + set r[i] = 0; + } + for (i in 2..L) { + AssertTwoOraclesAreEqual(i..i, Oracle_ProductFunction(_, _, r[0..i-1]), Oracle_Zero_Reference); + } + + // 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; + } + + set r = [1; 0; 1; 0; 1; 0]; + AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference); + + set r = [1; 0; 0; 1]; + AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference); + + set r = [0; 0; 1; 1; 1]; + AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductFunction, Oracle_ProductFunction_Reference); + } + } + + operation T16_Oracle_ProductWithNegationFunction_Test () : () + { + body + { + // cross-tests + // the mask for all 1's corresponds to Oracle_OddNumberOfOnes + mutable r = [1; 1; 1; 1; 1; 1; 1; 1; 1; 1]; + let L = Length(r); + for (i in 2..L) { + AssertTwoOraclesAreEqual(i..i, Oracle_ProductWithNegationFunction(_, _, r[0..i-1]), Oracle_OddNumberOfOnes_Reference); + } + + set r = [1; 0; 1; 0; 1; 0]; + AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference); + + set r = [1; 0; 0; 1]; + AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference); + + set r = [0; 0; 1; 1; 1]; + AssertTwoOraclesWithIntAreEqual(r, Oracle_ProductWithNegationFunction, Oracle_ProductWithNegationFunction_Reference); + } + } + + operation T17_Oracle_HammingWithPrefix_Test () : () + { + body + { + mutable prefix = [1]; + AssertTwoOraclesAreEqual(1..10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix)); + + set prefix = [1; 0]; + AssertTwoOraclesAreEqual(2..10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix)); + + set prefix = [0; 0; 0]; + AssertTwoOraclesAreEqual(3..10, Oracle_HammingWithPrefix(_, _, prefix), Oracle_HammingWithPrefix_Reference(_, _, prefix)); + } + } + + operation T18_Oracle_MajorityFunction_Test () : () + { + body + { + AssertTwoOraclesAreEqual(3..3, Oracle_MajorityFunction, Oracle_MajorityFunction_Reference); + } + } + + // ------------------------------------------------------ + operation T21_BV_StatePrep_Test () : () + { + body + { + for (N in 1..10) { + using (qs = Qubit[N+1]) + { + // apply operation that needs to be tested + BV_StatePrep(qs[0..N-1], qs[N]); + + // apply adjoint reference operation + (Adjoint BV_StatePrep_Reference)(qs[0..N-1], qs[N]); + + // assert that all qubits end up in |0〉 state + AssertAllZero(qs); + } + } + } + } + + // ------------------------------------------------------ + function AssertOracleCallsCount<'T>(count: Int, oracle: 'T) : () { } + + // ------------------------------------------------------ + function ResetOracleCallsCount() : () { } + + // ------------------------------------------------------ + function AssertIntArrayEqual (actual : Int[], expected : Int[], message : String) : () { + let n = Length(actual); + if (n != Length(expected)) { + fail message; + } + for (idx in 0..(n-1)) { + if( actual[idx] != expected[idx] ) { + fail message; + } + } + } + + // ------------------------------------------------------ + function IntArrFromPositiveInt (n : Int, bits : Int) : Int[] { + let rbool = BoolArrFromPositiveInt(n, bits); + mutable r = new Int[bits]; + for (i in 0..bits-1) { + if (rbool[i]) { + set r[i] = 1; + } + } + return r; + } + + // ------------------------------------------------------ + operation AssertBVAlgorithmWorks (r : Int[]) : () + { + body + { + let oracle = Oracle_ProductFunction_Reference(_, _, r); + AssertIntArrayEqual(BV_Algorithm(Length(r), oracle), r, "Bernstein-Vazirani algorithm failed"); + AssertOracleCallsCount(1, oracle); + } + } + + operation T22_BV_Algorithm_Test () : () + { + body + { + ResetOracleCallsCount(); + + // test BV the way we suggest the learner to test it: + // apply the algorithm to reference oracles and check that the output is as expected + for (bits in 1..4) { + for (n in 0..2^bits-1) { + let r = IntArrFromPositiveInt(n, bits); + AssertBVAlgorithmWorks(r); + } + } + AssertBVAlgorithmWorks([1; 1; 1; 0; 0]); + AssertBVAlgorithmWorks([1; 0; 1; 0; 1; 0]); + } + } + + // ------------------------------------------------------ + operation AssertDJAlgorithmWorks(oracle: ((Qubit[], Qubit) => ()), expected : Bool, msg: String) : () + { + body + { + AssertBoolEqual(DJ_Algorithm(4, oracle), expected, msg); + AssertOracleCallsCount(1, oracle); + } + } + + operation T31_DJ_Algorithm_Test () : () + { + body + { + ResetOracleCallsCount(); + + // test DJ the way we suggest the learner to test it: + // apply the algorithm to reference oracles and check that the output is as expected + AssertBoolEqual(DJ_Algorithm(4, Oracle_Zero_Reference), true, "f(x) = 0 not identified as constant"); + AssertBoolEqual(DJ_Algorithm(4, Oracle_One_Reference), true, "f(x) = 1 not identified as constant"); + AssertBoolEqual(DJ_Algorithm(4, Oracle_Kth_Qubit_Reference(_, _, 1)), false, "f(x) = x_k not identified as balanced"); + AssertBoolEqual(DJ_Algorithm(4, Oracle_OddNumberOfOnes_Reference), false, "f(x) = sum of x_i not identified as balanced"); + AssertBoolEqual(DJ_Algorithm(4, Oracle_ProductFunction_Reference(_, _, [1; 0; 1; 1])), false, "f(x) = sum of r_i x_i not identified as balanced"); + AssertBoolEqual(DJ_Algorithm(4, Oracle_ProductWithNegationFunction_Reference(_, _, [1; 0; 1; 1])), false, "f(x) = sum of r_i x_i + (1 - r_i)(1 - x_i) not identified as balanced"); + AssertBoolEqual(DJ_Algorithm(4, Oracle_HammingWithPrefix_Reference(_, _, [0; 1])), false, "f(x) = sum of x_i + 1 if prefix equals given not identified as balanced"); + AssertBoolEqual(DJ_Algorithm(3, Oracle_MajorityFunction_Reference), false, "f(x) = majority function not identified as balanced"); + } + } + + // ------------------------------------------------------ + operation AssertNonameAlgorithmWorks (r : Int[]) : () + { + body + { + let givenOracle = Oracle_ProductWithNegationFunction_Reference(_, _, r); + let res = Noname_Algorithm(Length(r), givenOracle); + + // check that the oracle was called once (later it will be called again by test harness) + AssertOracleCallsCount(1, givenOracle); + + // 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."); + let resOracle = Oracle_ProductWithNegationFunction_Reference(_, _, res); + AssertTwoOraclesAreEqual(Length(r)..Length(r), givenOracle, resOracle); + } + } + + operation CallNonameAlgoOnInt (n : Int, bits : Int) : () + { + body + { + let r = IntArrFromPositiveInt(n, bits); + AssertNonameAlgorithmWorks(r); + } + } + + operation T41_Noname_Algorithm_Test () : () + { + body + { + ResetOracleCallsCount(); + + // apply the algorithm to reference oracles and check that the output is as expected + // test all bit vectors of length 1..4 + for (bits in 1..4) { + for (n in 0..2^bits-1) { + CallNonameAlgoOnInt(n, bits); + } + } + // and a couple of random ones + AssertNonameAlgorithmWorks([1; 1; 1; 0; 0]); + AssertNonameAlgorithmWorks([1; 0; 1; 0; 1; 0]); + } + } +} \ No newline at end of file diff --git a/Measurements/.vscode/extensions.json b/Measurements/.vscode/extensions.json new file mode 100644 index 00000000000..14d152e069a --- /dev/null +++ b/Measurements/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "quantum.quantum-devkit-vscode" + ] +} \ No newline at end of file diff --git a/Measurements/.vscode/tasks.json b/Measurements/.vscode/tasks.json new file mode 100644 index 00000000000..bae788317e9 --- /dev/null +++ b/Measurements/.vscode/tasks.json @@ -0,0 +1,36 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "args": [ + "build" + ], + "type": "process", + "group": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + }, + { + "label": "test", + "command": "dotnet", + "args": [ + "test" + ], + "type": "process", + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Measurements/Measurements.csproj b/Measurements/Measurements.csproj new file mode 100644 index 00000000000..beddaeaf7fd --- /dev/null +++ b/Measurements/Measurements.csproj @@ -0,0 +1,22 @@ + + + netcoreapp2.0 + x64 + false + Quantum.Kata.Measurements + + + + + + + + + + + + + + + + diff --git a/Measurements/Measurements.sln b/Measurements/Measurements.sln new file mode 100644 index 00000000000..2768c3ab468 --- /dev/null +++ b/Measurements/Measurements.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Measurements", "Measurements.csproj", "{F7A0175F-4217-4343-8A3C-EA68FAAB6B7B}" +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 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4E22BDB7-FE55-4D1C-98FA-BD7612C8525D} + EndGlobalSection +EndGlobal diff --git a/Measurements/README.md b/Measurements/README.md new file mode 100644 index 00000000000..6416bc925f9 --- /dev/null +++ b/Measurements/README.md @@ -0,0 +1,11 @@ +# Welcome! + +The measurements kata covers the following topics: +- single-qubit measurements +- joint measurements +- quantum state discrimination for both orthogonal and non-orthogonal states + +Variations of quantum state discrimination tasks are covered in the paper ["Quantum State Discrimination"](https://arxiv.org/pdf/quant-ph/0010114.pdf). +* Task 2.1 is an example of hypothesis testing for two pure states. +* Task 2.2 is an example of unambiguous state discrimination. See also the paper ["Unambiguous quantum measurement of nonorthogonal states"](https://www.researchgate.net/publication/13375059_Unambiguous_quantum_measurement_of_nonorthogonal_states) + for further information and hints about how to implement the unambiguous measurements required for this task. diff --git a/Measurements/ReferenceImplementation.qs b/Measurements/ReferenceImplementation.qs new file mode 100644 index 00000000000..ba787d507e1 --- /dev/null +++ b/Measurements/ReferenceImplementation.qs @@ -0,0 +1,414 @@ +// 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.Measurements +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Convert; + open Microsoft.Quantum.Extensions.Math; + + ////////////////////////////////////////////////////////////////// + // Part I. Single-Qubit Measurements + ////////////////////////////////////////////////////////////////// + + // Task 1.1. |0〉 or |1〉 ? + // Input: a qubit which is guaranteed to be in |0〉 or |1〉 state. + // Output: true if qubit was in |1〉 state, or false if it was in |0〉 state. + // The state of the qubit at the end of the operation does not matter. + operation IsQubitOne_Reference (q : Qubit) : Bool + { + body + { + let res = M(q); + return res == One; + } + } + + // Task 1.2. |+〉 or |-〉 ? + // Input: a qubit which is guaranteed to be in |+〉 or |-〉 state + // (|+〉 = (|0〉 + |1〉) / sqrt(2), |-〉 = (|0〉 - |1〉) / sqrt(2)). + // Output: true if qubit was in |+〉 state, or false if it was in |-〉 state. + // The state of the qubit at the end of the operation does not matter. + operation IsQubitPlus_Reference (q : Qubit) : Bool + { + body + { + H(q); + let res = M(q); + return res == Zero; + } + } + + // Task 1.3. |A〉 or |B〉 ? + // Inputs: + // 1) angle alpha, in radians, represented as Double + // 2) a qubit which is guaranteed to be in |A〉 or |B〉 state + // |A〉 = cos(alpha) * |0〉 + sin(alpha) * |1〉, + // |B〉 = - sin(alpha) * |0〉 + cos(alpha) * |1〉. + // Output: true if qubit was in |A〉 state, or false if it was in |B〉 state. + // The state of the qubit at the end of the operation does not matter. + operation IsQubitA_Reference (alpha : Double, q : Qubit) : Bool + { + body + { + // |0〉 is converted into |A〉 and |1〉 into |B〉 by Ry(2.0 * alpha) + // so |A〉 is converted into |0〉 by the opposite rotation + Ry(- 2.0 * alpha, q); + let res = M(q); + return res == Zero; + } + } + + // Task 1.4. |00〉 or |11〉 ? + // Input: two qubits (stored in an array) which are guaranteed to be in |00〉 or |11〉 state. + // Output: 0 if qubits were in |00〉 state, + // 1 if they were in |11〉 state. + // The state of the qubits at the end of the operation does not matter. + operation ZeroZeroOrOneOne_Reference (qs : Qubit[]) : Int + { + body + { + // it's enough to do one measurement on any qubit + let res = M(qs[0]); + if (res == Zero) { + return 0; + } else { + return 1; + } + } + } + + // Task 1.5. Distinguish four basis states + // Input: two qubits (stored in an array) which are guaranteed to be + // in one of the four basis states (|00〉, |01〉, |10〉 or |11〉). + // Output: 0 if qubits were in |00〉 state, + // 1 if they were in |01〉 state, + // 2 if they were in |10〉 state, + // 3 if they were in |11〉 state. + // The state of the qubits at the end of the operation does not matter. + operation BasisStateMeasurement_Reference (qs : Qubit[]) : Int + { + body + { + // measurement on the first qubit gives the higher bit of the answer, on the second - the lower + mutable m1 = 0; + if (M(qs[0]) == One) { + set m1 = 1; + } + mutable m2 = 0; + if (M(qs[1]) == One) { + set m2 = 1; + } + return m1 * 2 + m2; + } + } + + // Task 1.6. Distinguish two basis states given by bit strings + // Inputs: + // 1) N qubits (stored in an array) which are guaranteed to be + // in one of the two basis states described by the given bit strings. + // 2) two bit string represented as Bool[]s. + // Output: 0 if qubits were in the basis state described by the first bit string, + // 1 if they were in the basis state described by the second bit string. + // Bit values false and true correspond to |0〉 and |1〉 states. + // The state of the qubits at the end of the operation does not matter. + // You are guaranteed that the both bit strings have the same length as the qubit array, + // and that the bit strings will differ in at least one bit. + // You can use exactly one measurement. + // Example: for bit strings [false; true; false] and [false; false; true] + // return 0 corresponds to state |010〉, and return 1 corresponds to state |001〉. + + function FindFirstDiff_Reference (bits1 : Bool[], bits2 : Bool[]) : Int + { + mutable firstDiff = -1; + for (i in 0 .. Length(bits1)-1) { + if (bits1[i] != bits2[i] && firstDiff == -1) { + set firstDiff = i; + } + } + return firstDiff; + } + + operation TwoBitstringsMeasurement_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Int + { + body + { + // find the first index at which the bit strings are different and measure it + let firstDiff = FindFirstDiff_Reference(bits1, bits2); + let res = (M(qs[firstDiff]) == One); + if (res == bits1[firstDiff]) { + return 0; + } else { + return 1; + } + } + } + + // Task 1.7. |0...0〉 state or W state ? + // Input: N qubits (stored in an array) which are guaranteed to be + // either in |0...0〉 state + // or in W state (https://en.wikipedia.org/wiki/W_state). + // Output: 0 if qubits were in |0...0〉 state, + // 1 if they were in W state. + // The state of the qubits at the end of the operation does not matter. + operation AllZerosOrWState_Reference (qs : Qubit[]) : Int + { + body + { + // measure all qubits; if there is exactly one One, it's W state, if there are no Ones, it's |0...0〉 + // (and there should never be two or more Ones) + mutable countOnes = 0; + for (i in 0..Length(qs)-1) { + if (M(qs[i]) == One) { + set countOnes = countOnes + 1; + } + } + if (countOnes > 1) { + fail "Impossible to get multiple Ones when measuring W state"; + } + if (countOnes == 0) { + return 0; + } + return 1; + } + } + + // Task 1.8. GHZ state or W state ? + // Input: N qubits (stored in an array) which are guaranteed to be + // either in GHZ state (https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state) + // or in W state (https://en.wikipedia.org/wiki/W_state). + // Output: 0 if qubits were in GHZ state, + // 1 if they were in W state. + // The state of the qubits at the end of the operation does not matter. + operation GHZOrWState_Reference (qs : Qubit[]) : Int + { + body + { + // measure all qubits; if there is exactly one One, it's W state, + // if there are no Ones or all are Ones, it's GHZ + // (and there should never be a different number of Ones) + let N = Length(qs); + mutable countOnes = 0; + for (i in 0..N-1) { + if (M(qs[i]) == One) { + set countOnes = countOnes + 1; + } + } + if (countOnes > 1 && countOnes < Length(qs)) { + fail $"Impossible to get {countOnes} Ones when measuring W state or GHZ state on {N} qubits"; + } + if (countOnes == 1) { + return 1; + } + return 0; + } + } + + // Task 1.9. Distinguish four Bell states + // Input: two qubits (stored in an array) which are guaranteed to be in one of the four Bell states: + // |Φ⁺〉 = (|00〉 + |11〉) / sqrt(2) + // |Φ⁻〉 = (|00〉 - |11〉) / sqrt(2) + // |Ψ⁺〉 = (|01〉 + |10〉) / sqrt(2) + // |Ψ⁻〉 = (|01〉 - |10〉) / sqrt(2) + // Output: 0 if qubits were in |Φ⁺〉 state, + // 1 if they were in |Φ⁻〉 state, + // 2 if they were in |Ψ⁺〉 state, + // 3 if they were in |Ψ⁻〉 state. + // The state of the qubits at the end of the operation does not matter. + operation BellState_Reference (qs : Qubit[]) : Int + { + body + { + H(qs[0]); + H(qs[1]); + CNOT(qs[1], qs[0]); + H(qs[1]); + mutable m1 = 0; + if (M(qs[0]) == One) { + set m1 = 1; + } + mutable m2 = 0; + if (M(qs[1]) == One) { + set m2 = 1; + } + return m2 * 2 + m1; + } + } + + // Task 1.10*. Distinguish four orthogonal 2-qubit states + // Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states: + // |S0〉 = (|00〉 + |01〉 + |10〉 + |11〉) / 2 + // |S1〉 = (|00〉 - |01〉 + |10〉 - |11〉) / 2 + // |S2〉 = (|00〉 + |01〉 - |10〉 - |11〉) / 2 + // |S3〉 = (|00〉 - |01〉 - |10〉 + |11〉) / 2 + // Output: 0 if qubits were in |S0〉 state, + // 1 if they were in |S1〉 state, + // 2 if they were in |S2〉 state, + // 3 if they were in |S3〉 state. + // The state of the qubits at the end of the operation does not matter. + operation TwoQubitState_Reference (qs : Qubit[]) : Int + { + body + { + // These states are produced by H ⊗ H, applied to four basis states. + // To measure them, apply H ⊗ H followed by basis state measurement + // implemented in BasisStateMeasurement_Reference. + H(qs[0]); + H(qs[1]); + return BasisStateMeasurement_Reference(qs); + } + } + + // Task 1.11**. Distinguish four orthogonal 2-qubit states, part two + // Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states: + // |S0〉 = ( |00〉 - |01〉 - |10〉 - |11〉) / 2 + // |S1〉 = (-|00〉 + |01〉 - |10〉 - |11〉) / 2 + // |S2〉 = (-|00〉 - |01〉 + |10〉 - |11〉) / 2 + // |S3〉 = (-|00〉 - |01〉 - |10〉 + |11〉) / 2 + // Output: 0 if qubits were in |S0〉 state, + // 1 if they were in |S1〉 state, + // 2 if they were in |S2〉 state, + // 3 if they were in |S3〉 state. + // The state of the qubits at the end of the operation does not matter. + + // Helper function to implement diag(-1, 1, 1, 1) + operation ApplyDiag (qs : Qubit[]) : () + { + body + { + ApplyToEach(X, qs); + (Controlled Z)([qs[0]], qs[1]); + ApplyToEach(X, qs); + } + adjoint self + } + + // The actual reference implementation for Task 1.11 + operation TwoQubitStatePartTwo_Reference (qs : Qubit[]) : Int + { + body + { + // Observe that the unitary matrix A formed by the columns |S0〉, ..., |S3〉 + // is up to permutations matrices and diagonal +1/-1 matrices equal to the + // tensor product H ⊗ H when multiplied from the left and the right. + // Specifically, A = diag(-1, 1, 1, 1) (H ⊗ H) diag(-1, 1, 1, 1) pi, + // where pi is the permutation (1,2) corresponding to a swap of 2 qubits. + SWAP(qs[0], qs[1]); // pi + With(ApplyDiag, ApplyToEach(H, _), qs); // diag(..) (H ⊗ H) diag(..) + return BasisStateMeasurement_Reference(qs); + } + } + + + ////////////////////////////////////////////////////////////////// + // Part II*. Discriminating Nonorthogonal States + ////////////////////////////////////////////////////////////////// + + // Task 2.1*. |0〉 or |+〉 ? + // (quantum hypothesis testing or state discrimination with minimum error) + // Input: a qubit which is guaranteed to be in |0〉 or |+〉 state with equal probability. + // Output: true if qubit was in |0〉 state, or false if it was in |+〉 state. + // The state of the qubit at the end of the operation does not matter. + // Note: in this task you have to get accuracy of at least 80%. + operation IsQubitPlusOrZero_Reference (q : Qubit) : Bool + { + body + { + // Let {E_a, E_b} be a measurement with two outcomes a and b, which we identify with + // the answers, i.e., "a" = "state was |0〉" and "b = state was |+〉". Then we define + // P(a|0) = probability to observe first outcome given that the state was |0〉 + // P(b|0) = probability to observe second outcome given that the state was |0〉 + // P(a|+) = probability to observe first outcome given that the state was |+〉 + // P(b|+) = probability to observe second outcome given that the state was |+〉 + // the task is to maximize the probability to be correct on a single shot experiment + // which is the same as to minimize the probability to be wrong (on a single shot). + // Assuming uniform prior, i.e., P(+) = P(0) = 1/2, we get + // P_correct = P(0) P(a|0) + P(+) P(b|+). Assuming a von Neumann measurement of the + // form E_a = Ry(2*alpha) * (1,0) = (cos(alpha), sin(alpha)) and + // E_b = Ry(2*alpha) * (0,1) = (sin(alpha), -cos(alpha)), we get that + // P_correct = 1/2 + cos²(alpha) + cos(alpha) sin(alpha). Maximizing this for alpha, + // we get max P_success = 1/2 (1 + 1/sqrt(2)) = 0.8535.., which is attained for alpha = π/8. + + // Rotate the input state by π/8 means to apply Ry with angle 2π/8. + Ry(0.25*PI(), q); + return (M(q) == Zero); + } + } + + // Task 2.2**. |0〉, |+〉 or inconclusive? + // (unambiguous state discrimination) + // Input: a qubit which is guaranteed to be in |0〉 or |+〉 state with equal probability. + // Output: 0 if qubit was in |0〉 state, + // 1 if it was in |+〉 state, + // -1 if you can't decide, i.e., an "inconclusive" result. + // Your solution: + // - can never give 0 or 1 answer incorrectly (i.e., identify |0〉 as 1 or |+〉 as 0). + // - must give inconclusive (-1) answer at most 80% of the times. + // - must correctly identify |0〉 state as 0 at least 10% of the times. + // - must correctly identify |1〉 state as 1 at least 10% of the times. + // + // The state of the qubit at the end of the operation does not matter. + // You are allowed to use ancilla qubit(s). + operation IsQubitPlusZeroOrInconclusiveSimpleUSD_Reference (q : Qubit) : Int + { + body + { + // A simple strategy that gives an inconclusive result with probability 0.75 + // and never errs in case it yields a conclusive result can be obtained from + // randomizing the choice of measurement basis between the computational basis (std) + // and the Hadamard basis (had). Observe that when measured in the standard basis, + // the state |0〉 will always lead to the outcome "0", whereas the state |+〉 + // will lead to outcomes "0" respectively "1" with probability 1/2. This means + // that upon measuring "1" we can with certainty conclude that the state was |+〉. + // A similar argument applies to the scenario where we measure in the Hadamard + // basis, where |0〉 can lead to both outcomes, whereas |+〉 always leads to "0". + // Then upon measuring "1" we can with certainty conclude that the state was |0〉. + // + // This leads to the following scenarios (shown are the conditional probabilities + // of the above scenarios and resulting answers). + // state | basis | output 0 | output 1 | output -1 + // ----------------------------------------------- + // |0〉 | std | 0 | 0 | 1 + // |+〉 | 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 + + if (basis == 0) { + // 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; + } + } + 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; + } + } + return output; + } + } +} diff --git a/Measurements/Tasks.qs b/Measurements/Tasks.qs new file mode 100644 index 00000000000..117adb2c5c6 --- /dev/null +++ b/Measurements/Tasks.qs @@ -0,0 +1,276 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Quantum.Kata.Measurements +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Convert; + open Microsoft.Quantum.Extensions.Math; + + ////////////////////////////////////////////////////////////////// + // Welcome! + ////////////////////////////////////////////////////////////////// + + // "Measurements" quantum kata is a series of exercises designed + // to get you familiar with programming in Q#. + // It covers the following topics: + // - single-qubit measurements, + // - joint measurements, + // - discriminating orthogonal and nonorthogonal states. + // + // 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 Measurements + ////////////////////////////////////////////////////////////////// + + // Task 1.1. |0〉 or |1〉 ? + // Input: a qubit which is guaranteed to be in |0〉 or |1〉 state. + // Output: true if qubit was in |1〉 state, or false if it was in |0〉 state. + // The state of the qubit at the end of the operation does not matter. + operation IsQubitOne (q : Qubit) : Bool + { + body + { + // ... + return false; + } + } + + // Task 1.2. |+〉 or |-〉 ? + // Input: a qubit which is guaranteed to be in |+〉 or |-〉 state + // (|+〉 = (|0〉 + |1〉) / sqrt(2), |-〉 = (|0〉 - |1〉) / sqrt(2)). + // Output: true if qubit was in |+〉 state, or false if it was in |-〉 state. + // The state of the qubit at the end of the operation does not matter. + operation IsQubitPlus (q : Qubit) : Bool + { + body + { + // ... + return false; + } + } + + // Task 1.3. |A〉 or |B〉 ? + // Inputs: + // 1) angle alpha, in radians, represented as Double + // 2) a qubit which is guaranteed to be in |A〉 or |B〉 state + // |A〉 = cos(alpha) * |0〉 + sin(alpha) * |1〉, + // |B〉 = - sin(alpha) * |0〉 + cos(alpha) * |1〉. + // Output: true if qubit was in |A〉 state, or false if it was in |B〉 state. + // The state of the qubit at the end of the operation does not matter. + operation IsQubitA (alpha : Double, q : Qubit) : Bool + { + body + { + // ... + return false; + } + } + + // Task 1.4. |00〉 or |11〉 ? + // Input: two qubits (stored in an array) which are guaranteed to be in |00〉 or |11〉 state. + // Output: 0 if qubits were in |00〉 state, + // 1 if they were in |11〉 state. + // The state of the qubits at the end of the operation does not matter. + operation ZeroZeroOrOneOne (qs : Qubit[]) : Int + { + body + { + // ... + return -1; + } + } + + // Task 1.5. Distinguish four basis states + // Input: two qubits (stored in an array) which are guaranteed to be + // in one of the four basis states (|00〉, |01〉, |10〉 or |11〉). + // Output: 0 if qubits were in |00〉 state, + // 1 if they were in |01〉 state, + // 2 if they were in |10〉 state, + // 3 if they were in |11〉 state. + // In this task and the subsequent ones the order of qubit states + // in task description matches the order of qubits in the array + // (i.e., |10〉 state corresponds to qs[0] in state |1〉 and qs[1] in state |0〉). + // The state of the qubits at the end of the operation does not matter. + operation BasisStateMeasurement (qs : Qubit[]) : Int + { + body + { + // ... + return -1; + } + } + + // Task 1.6. Distinguish two basis states given by bit strings + // Inputs: + // 1) N qubits (stored in an array) which are guaranteed to be + // in one of the two basis states described by the given bit strings. + // 2) two bit string represented as Bool[]s. + // Output: 0 if qubits were in the basis state described by the first bit string, + // 1 if they were in the basis state described by the second bit string. + // Bit values false and true correspond to |0〉 and |1〉 states. + // The state of the qubits at the end of the operation does not matter. + // You are guaranteed that the both bit strings have the same length as the qubit array, + // and that the bit strings will differ in at least one bit. + // You can use exactly one measurement. + // Example: for bit strings [false; true; false] and [false; false; true] + // return 0 corresponds to state |010〉, and return 1 corresponds to state |001〉. + operation TwoBitstringsMeasurement (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : Int + { + body + { + // ... + return -1; + } + } + + // Task 1.7. |0...0〉 state or W state ? + // Input: N qubits (stored in an array) which are guaranteed to be + // either in |0...0〉 state + // or in W state (https://en.wikipedia.org/wiki/W_state). + // Output: 0 if qubits were in |0...0〉 state, + // 1 if they were in W state. + // The state of the qubits at the end of the operation does not matter. + operation AllZerosOrWState (qs : Qubit[]) : Int + { + body + { + // ... + return -1; + } + } + + // Task 1.8. GHZ state or W state ? + // Input: N qubits (stored in an array) which are guaranteed to be + // either in GHZ state (https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state) + // or in W state (https://en.wikipedia.org/wiki/W_state). + // Output: 0 if qubits were in GHZ state, + // 1 if they were in W state. + // The state of the qubits at the end of the operation does not matter. + operation GHZOrWState (qs : Qubit[]) : Int + { + body + { + // ... + return -1; + } + } + + // Task 1.9. Distinguish four Bell states + // Input: two qubits (stored in an array) which are guaranteed to be in one of the four Bell states: + // |Φ⁺〉 = (|00〉 + |11〉) / sqrt(2) + // |Φ⁻〉 = (|00〉 - |11〉) / sqrt(2) + // |Ψ⁺〉 = (|01〉 + |10〉) / sqrt(2) + // |Ψ⁻〉 = (|01〉 - |10〉) / sqrt(2) + // Output: 0 if qubits were in |Φ⁺〉 state, + // 1 if they were in |Φ⁻〉 state, + // 2 if they were in |Ψ⁺〉 state, + // 3 if they were in |Ψ⁻〉 state. + // The state of the qubits at the end of the operation does not matter. + operation BellState (qs : Qubit[]) : Int + { + body + { + // Hint: you need to use 2-qubit gates to solve this task + + // ... + return -1; + } + } + + // Task 1.10*. Distinguish four orthogonal 2-qubit states + // Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states: + // |S0〉 = (|00〉 + |01〉 + |10〉 + |11〉) / 2 + // |S1〉 = (|00〉 - |01〉 + |10〉 - |11〉) / 2 + // |S2〉 = (|00〉 + |01〉 - |10〉 - |11〉) / 2 + // |S3〉 = (|00〉 - |01〉 - |10〉 + |11〉) / 2 + // Output: 0 if qubits were in |S0〉 state, + // 1 if they were in |S1〉 state, + // 2 if they were in |S2〉 state, + // 3 if they were in |S3〉 state. + // The state of the qubits at the end of the operation does not matter. + operation TwoQubitState (qs : Qubit[]) : Int + { + body + { + // ... + return -1; + } + } + + // Task 1.11**. Distinguish four orthogonal 2-qubit states, part two + // Input: two qubits (stored in an array) which are guaranteed to be in one of the four orthogonal states: + // |S0〉 = ( |00〉 - |01〉 - |10〉 - |11〉) / 2 + // |S1〉 = (-|00〉 + |01〉 - |10〉 - |11〉) / 2 + // |S2〉 = (-|00〉 - |01〉 + |10〉 - |11〉) / 2 + // |S3〉 = (-|00〉 - |01〉 - |10〉 + |11〉) / 2 + // Output: 0 if qubits were in |S0〉 state, + // 1 if they were in |S1〉 state, + // 2 if they were in |S2〉 state, + // 3 if they were in |S3〉 state. + // The state of the qubits at the end of the operation does not matter. + operation TwoQubitStatePartTwo (qs : Qubit[]) : Int + { + body + { + // ... + return -1; + } + } + + + ////////////////////////////////////////////////////////////////// + // Part II*. Discriminating Nonorthogonal States + ////////////////////////////////////////////////////////////////// + + // The solutions for tasks in this section are validated using the following method. + // The solution is called on N input states, each of which is picked randomly, + // with all possible input states equally likely to be generated. + // The accuracy of state discrimination is estimated as an average of + // discrimination correctness over all input states. + + // Task 2.1*. |0〉 or |+〉 ? + // (quantum hypothesis testing or state discrimination with minimum error) + // Input: a qubit which is guaranteed to be in |0〉 or |+〉 state with equal probability. + // Output: true if qubit was in |0〉 state, or false if it was in |+〉 state. + // The state of the qubit at the end of the operation does not matter. + // Note: in this task you have to get accuracy of at least 80%. + operation IsQubitPlusOrZero (q : Qubit) : Bool + { + body + { + // ... + return true; + } + } + + // Task 2.2**. |0〉, |+〉 or inconclusive? + // (unambiguous state discrimination) + // Input: a qubit which is guaranteed to be in |0〉 or |+〉 state with equal probability. + // Output: 0 if qubit was in |0〉 state, + // 1 if it was in |+〉 state, + // -1 if you can't decide, i.e., an "inconclusive" result. + // Your solution: + // - can never give 0 or 1 answer incorrectly (i.e., identify |0〉 as 1 or |+〉 as 0). + // - must give inconclusive (-1) answer at most 80% of the times. + // - must correctly identify |0〉 state as 0 at least 10% of the times. + // - must correctly identify |1〉 state as 1 at least 10% of the times. + // + // The state of the qubit at the end of the operation does not matter. + // You are allowed to use ancilla qubit(s). + operation IsQubitPlusZeroOrInconclusiveSimpleUSD (q : Qubit) : Int + { + body + { + // ... + return -2; + } + } +} \ No newline at end of file diff --git a/Measurements/TestSuiteRunner.cs b/Measurements/TestSuiteRunner.cs new file mode 100644 index 00000000000..3372c46f245 --- /dev/null +++ b/Measurements/TestSuiteRunner.cs @@ -0,0 +1,42 @@ +// 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 Microsoft.Quantum.Simulation.Simulators; +using Xunit.Abstractions; +using System.Diagnostics; + +namespace Quantum.Kata.Measurements +{ + public class TestSuiteRunner + { + private readonly ITestOutputHelper output; + + public TestSuiteRunner(ITestOutputHelper output) + { + this.output = output; + } + + /// + /// This driver will run all Q# tests (operations named "...Test") + /// that belong to namespace Quantum.Kata.Measurements. + /// + [OperationDriver(TestNamespace = "Quantum.Kata.Measurements")] + public void TestTarget(TestOperation op) + { + using (var sim = new QuantumSimulator()) + { + // 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); + } + } + } +} diff --git a/Measurements/Tests.qs b/Measurements/Tests.qs new file mode 100644 index 00000000000..ac02b343ff9 --- /dev/null +++ b/Measurements/Tests.qs @@ -0,0 +1,533 @@ +// 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.Measurements +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Convert; + open Microsoft.Quantum.Extensions.Math; + open Microsoft.Quantum.Extensions.Testing; + + ////////////////////////////////////////////////////////////////// + + // "Framework" operation for testing single-qubit tasks for distinguishing states of one qubit + // with Bool return + operation DistinguishTwoStates_OneQubit ( + statePrep : ((Qubit, Int) => ()), + testImpl : (Qubit => Bool) + ) : () + { + body + { + let nTotal = 100; + mutable nOk = 0; + using (qs = Qubit[1]) + { + for (i in 1..nTotal) + { + // get a random bit to define whether qubit will be in a state corresponding to true return (1) or to false one (0) + // state = 0 false return + // state = 1 true return + let state = RandomIntPow2(1); + + // do state prep: convert |0〉 to outcome with false return or to outcome with true return depending on state + statePrep(qs[0], state); + + // 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; + } + + // we're not checking the state of the qubit after the operation + Reset(qs[0]); + } + } + AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state."); + } + } + + // ------------------------------------------------------ + operation StatePrep_IsQubitOne (q : Qubit, state : Int) : () { + body { + if (state == 0) { + // convert |0〉 to |0〉 + } else { + // convert |0〉 to |1〉 + X(q); + } + } + } + + operation T101_IsQubitOne_Test () : () + { + body + { + DistinguishTwoStates_OneQubit(StatePrep_IsQubitOne, IsQubitOne); + } + } + + // ------------------------------------------------------ + operation StatePrep_IsQubitPlus (q : Qubit, state : Int) : () { + body { + if (state == 0) { + // convert |0〉 to |-〉 + X(q); + H(q); + } else { + // convert |0〉 to |+〉 + H(q); + } + } + } + + operation T102_IsQubitPlus_Test () : () + { + body + { + DistinguishTwoStates_OneQubit(StatePrep_IsQubitPlus, IsQubitPlus); + } + } + + // ------------------------------------------------------ + // |A〉 = cos(alpha) * |0〉 + sin(alpha) * |1〉, + // |B〉 = - sin(alpha) * |0〉 + cos(alpha) * |1〉. + operation StatePrep_IsQubitA (alpha : Double, q : Qubit, state : Int) : () { + body { + if (state == 0) { + // convert |0〉 to |B〉 + X(q); + Ry(2.0 * alpha, q); + } else { + // convert |0〉 to |A〉 + Ry(2.0 * alpha, q); + } + } + } + + operation T103_IsQubitA_Test () : () + { + body + { + // cross-test + // alpha = 0.0 or PI() => !isQubitOne + // alpha = PI() / 2.0 => isQubitOne + DistinguishTwoStates_OneQubit(StatePrep_IsQubitOne, IsQubitA(PI() / 2.0, _)); + // alpha = PI() / 4.0 => isQubitPlus + DistinguishTwoStates_OneQubit(StatePrep_IsQubitPlus, IsQubitA(PI() / 4.0, _)); + + for (i in 0..10) { + let alpha = PI() * ToDouble(i) / 10.0; + DistinguishTwoStates_OneQubit(StatePrep_IsQubitA(alpha, _, _), IsQubitA(alpha, _)); + } + } + } + + // ------------------------------------------------------ + + // "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) => ()), + testImpl : (Qubit[] => Int) + ) : () + { + body + { + let nTotal = 100; + mutable nOk = 0; + using (qs = Qubit[Nqubit]) + { + for (i in 1..nTotal) + { + // get a random integer to define the state of the qubits + let state = RandomInt(Nstate); + + // do state prep: convert |0...0〉 to outcome with return equal to state + statePrep(qs, state); + + // get the solution's answer and verify that it's a match + let ans = testImpl(qs); + if (ans == state) { + set nOk = nOk + 1; + } + + // we're not checking the state of the qubit after the operation + ResetAll(qs); + } + } + AssertIntEqual(nOk, nTotal, $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state."); + } + } + + // ------------------------------------------------------ + operation StatePrep_ZeroZeroOrOneOne (qs : Qubit[], state : Int) : () { + body { + if (state == 1) { + // |11〉 + X(qs[0]); + X(qs[1]); + } + } + } + + operation T104_ZeroZeroOrOneOne_Test () : () { + body { + DistinguishStates_MultiQubit(2, 2, StatePrep_ZeroZeroOrOneOne, ZeroZeroOrOneOne); + } + } + + // ------------------------------------------------------ + operation StatePrep_BasisStateMeasurement (qs : Qubit[], state : Int) : () { + body { + if (state / 2 == 1) { + // |10〉 or |11〉 + X(qs[0]); + } + if (state % 2 == 1) { + // |01〉 or |11〉 + X(qs[1]); + } + } + } + + operation T105_BasisStateMeasurement_Test () : () { + body { + DistinguishStates_MultiQubit(2, 4, StatePrep_BasisStateMeasurement, BasisStateMeasurement); + } + } + + // ------------------------------------------------------ + operation StatePrep_Bitstring (qs : Qubit[], bits : Bool[]) : () { + body { + for (i in 0..Length(qs)-1) { + if (bits[i]) { + X(qs[i]); + } + } + } + } + + operation StatePrep_TwoBitstringsMeasurement (qs : Qubit[], bits1 : Bool[], bits2 : Bool[], state : Int) : () { + body { + if (state == 0) { + StatePrep_Bitstring(qs, bits1); + } else { + StatePrep_Bitstring(qs, bits2); + } + } + } + + operation T106_TwoBitstringsMeasurement_Test () : () { + body { + for (i in 1..1) { + let b1 = [false; true]; + let b2 = [true; false]; + DistinguishStates_MultiQubit(2, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2)); + } + for (i in 1..1) { + let b1 = [true; true; false]; + let b2 = [false; true; true]; + DistinguishStates_MultiQubit(3, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2)); + } + for (i in 1..1) { + let b1 = [false; true; true; false]; + let b2 = [false; true; true; true]; + DistinguishStates_MultiQubit(4, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2)); + } + for (i in 1..1) { + let b1 = [true; false; false; false]; + let b2 = [true; false; true; true]; + DistinguishStates_MultiQubit(4, 2, StatePrep_TwoBitstringsMeasurement(_, b1, b2, _), TwoBitstringsMeasurement(_, b1, b2)); + } + } + } + + // ------------------------------------------------------ + operation WState_Arbitrary_Reference (qs : Qubit[]) : () + { + body + { + 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 WState_Arbitrary_Reference)(qs[0..0], qs[1..N-1]); + X(qs[0]); + } + } + adjoint auto; + controlled auto; + adjoint controlled auto; + } + + operation StatePrep_AllZerosOrWState (qs : Qubit[], state : Int) : () { + body { + if (state == 1) { + // prep W state + WState_Arbitrary_Reference(qs); + } + } + } + + operation T107_AllZerosOrWState_Test () : () { + body { + for (i in 2..6) { + DistinguishStates_MultiQubit(i, 2, StatePrep_AllZerosOrWState, AllZerosOrWState); + } + } + } + + // ------------------------------------------------------ + operation GHZ_State_Reference (qs : Qubit[]) : () + { + body + { + H(qs[0]); + for (i in 1 .. Length(qs)-1) { + CNOT(qs[0], qs[i]); + } + } + adjoint auto; + } + + operation StatePrep_GHZOrWState (qs : Qubit[], state : Int) : () { + body { + if (state == 0) { + // prep GHZ state + GHZ_State_Reference(qs); + } else { + // prep W state + WState_Arbitrary_Reference(qs); + } + } + } + + operation T108_GHZOrWState_Test () : () { + body { + for (i in 2..6) { + DistinguishStates_MultiQubit(i, 2, StatePrep_GHZOrWState, GHZOrWState); + } + } + } + + // ------------------------------------------------------ + // 0 - |Φ⁺〉 = (|00〉 + |11〉) / sqrt(2) + // 1 - |Φ⁻〉 = (|00〉 - |11〉) / sqrt(2) + // 2 - |Ψ⁺〉 = (|01〉 + |10〉) / sqrt(2) + // 3 - |Ψ⁻〉 = (|01〉 - |10〉) / sqrt(2) + operation StatePrep_BellState (qs : Qubit[], state : Int) : () { + body { + 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]); + } + } + } + + operation T109_BellState_Test () : () { + body { + DistinguishStates_MultiQubit(2, 4, StatePrep_BellState, BellState); + } + } + + // ------------------------------------------------------ + // 0 - (|00〉 + |01〉 + |10〉 + |11〉) / 2 + // 1 - (|00〉 - |01〉 + |10〉 - |11〉) / 2 + // 2 - (|00〉 + |01〉 - |10〉 - |11〉) / 2 + // 3 - (|00〉 - |01〉 - |10〉 + |11〉) / 2 + operation StatePrep_TwoQubitState (qs : Qubit[], state : Int) : () { + body { + // start with state prep of basis vectors + StatePrep_BasisStateMeasurement(qs, state); + H(qs[0]); + H(qs[1]); + } + } + + // ------------------------------------------------------ + // 0 - ( |00〉 - |01〉 - |10〉 - |11〉) / 2 + // 1 - (-|00〉 + |01〉 - |10〉 - |11〉) / 2 + // 2 - (-|00〉 - |01〉 + |10〉 - |11〉) / 2 + // 3 - (-|00〉 - |01〉 - |10〉 + |11〉) / 2 + operation StatePrep_TwoQubitStatePartTwo (qs : Qubit[], state : Int) : () { + body { + // start with state prep of basis vectors + StatePrep_BasisStateMeasurement(qs, state); + // now apply all gates for unitary in reference impl (in reverse + adjoint) + ApplyToEach(X, qs); + (Controlled Z)([qs[0]], qs[1]); + ApplyToEach(X, qs); + ApplyToEach(H, qs); + ApplyToEach(X, qs); + (Controlled Z)([qs[0]], qs[1]); + ApplyToEach(X, qs); + SWAP(qs[0], qs[1]); + } + } + + operation T110_TwoQubitState_Test () : () { + body { + DistinguishStates_MultiQubit(2, 4, StatePrep_TwoQubitState, TwoQubitState); + } + } + + operation T111_TwoQubitStatePartTwo_Test () : () { + body { + DistinguishStates_MultiQubit(2, 4, StatePrep_TwoQubitStatePartTwo, TwoQubitStatePartTwo); + } + } + + ////////////////////////////////////////////////////////////////// + + operation StatePrep_IsQubitZeroOrPlus (q : Qubit, state : Int) : () { + body { + if (state == 0) { + // convert |0〉 to |0〉 + } else { + // convert |0〉 to |+〉 + H(q); + } + } + } + + + // "Framework" operation for testing multi-qubit tasks for distinguishing states of an array of qubits + // with Int return. Framework tests against a threshold parameter for the fraction of runs that must succeed. + operation DistinguishStates_MultiQubit_Threshold ( + Nqubit : Int, + Nstate : Int, + threshold : Double, + statePrep : ((Qubit, Int) => ()), + testImpl : (Qubit => Bool) + ) : () + { + body + { + let nTotal = 1000; + mutable nOk = 0; + using (qs = Qubit[Nqubit]) + { + for (i in 1..nTotal) + { + // get a random integer to define the state of the qubits + let state = RandomInt(Nstate); + + // do state prep: convert |0〉 to outcome with return equal to state + statePrep(qs[0], state); + // 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; + } + + // we're not checking the state of the qubit after the operation + ResetAll(qs); + } + } + if (ToDouble(nOk) < threshold * ToDouble(nTotal)) { + fail $"{nTotal - nOk} test runs out of {nTotal} returned incorrect state which does not meet the required threshold of at least {threshold*100}%."; + } + } + } + + + // "Framework" operation for testing multi-qubit tasks for distinguishing states of an array of qubits + // with Int return. Framework tests against a threshold parameter for the fraction of runs that must succeed. + // Framework tests in the USD scenario, i.e., it is allowed to respond "inconclusive" (with some probability) + // up to given threshold, but it is never allowed to err if an actual conclusive response is given. + operation USD_DistinguishStates_MultiQubit_Threshold ( + Nqubit : Int, + Nstate : Int, + thresholdInconcl : Double, + thresholdConcl : Double, + statePrep : ((Qubit, Int) => ()), + testImpl : (Qubit => Int) + ) : () + { + body + { + let nTotal = 10000; + mutable nInconc = 0; // counts total inconclusive answers + mutable nConclOne = 0; // counts total conclusive |0〉 state identifications + mutable nConclPlus = 0; // counts total conclusive |+> state identifications + + using (qs = Qubit[Nqubit]) + { + for (i in 1..nTotal) + { + // get a random integer to define the state of the qubits + let state = RandomInt(Nstate); + // do state prep: convert |0〉 to outcome with return equal to state + statePrep(qs[0], state); + // get the solution's answer and verify that it's a match + let ans = testImpl(qs[0]); + // check that the answer is actually in allowed range + if (ans < -1 || ans > 1) { + fail $"state {state} led to invalid response {ans}."; + } + // keep track of the number of inconclusive answers given + if (ans == -1) { + set nInconc = nInconc + 1; + } + if (ans == 0 && state == 0) { + set nConclOne = nConclOne + 1; + } + if (ans == 1 && state == 1) { + set nConclPlus = nConclPlus + 1; + } + // check if upon conclusive result the answer is actually correct + if ((ans == 0) && (state == 1) || (ans == 1) && (state == 0)) { + fail $"state {state} led to incorrect conclusive response {ans}."; + } + // we're not checking the state of the qubit after the operation + ResetAll(qs); + } + } + if (ToDouble(nInconc) > thresholdInconcl * ToDouble(nTotal)) { + fail $"{nInconc} test runs out of {nTotal} returned inconclusive which does not meet the required threshold of at most {thresholdInconcl*100}%."; + } + if (ToDouble(nConclOne) < thresholdConcl * ToDouble(nTotal)) { + fail $"Only {nConclOne} test runs out of {nTotal} returned conclusive |0〉 which does not meet the required threshold of at least {thresholdConcl*100}%."; + } + if (ToDouble(nConclPlus) < thresholdConcl * ToDouble(nTotal)) { + fail $"Only {nConclPlus} test runs out of {nTotal} returned conclusive |+> which does not meet the required threshold of at least {thresholdConcl*100}%."; + } + } + } + + operation T201_IsQubitZeroOrPlus_Test () : () { + body { + DistinguishStates_MultiQubit_Threshold(1, 2, 0.8, StatePrep_IsQubitZeroOrPlus, IsQubitPlusOrZero); + } + } + + operation T202_IsQubitZeroOrPlusSimpleUSD_Test () : () { + body { + USD_DistinguishStates_MultiQubit_Threshold(1, 2, 0.8, 0.1, StatePrep_IsQubitZeroOrPlus, IsQubitPlusZeroOrInconclusiveSimpleUSD); + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 72f1506a93b..f9f06738dd2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,105 @@ +# Introduction + +The Quantum Katas are a series of self-paced tutorials aimed at teaching you elements of quantum computing and Q# programming at the same time. + +Each kata covers one topic. +Currently covered topics are: + +* **[Basic quantum computing gates](./BasicGates/)**. + Tasks which focus on main single-qubit and multi-qubit gates used in quantum computing. +* **[Superposition](./Superposition/)**. + Tasks which focus on preparing a certain superposition state on one or multiple qubits. +* **[Measurements](./Measurements/)**. + Tasks which focus on distinguishing quantum states using measurements. +* **[Deutsch–Jozsa algorithm](./DeutschJozsaAlgorithm/)**. + Tasks which focus on writing quantum oracles which implement classical functions, and the Bernstein–Vazirani and Deutsch–Jozsa algorithms. + +Each kata is a separate project which includes: + +* A sequence of tasks on the topic progressing from trivial to challenging. + Each task requires you to fill in some code; the first task might require just one line, and the last one might require a sizable fragment of code. +* A testing framework that sets up, runs and validates your solutions. + Each task is covered by a [*unit test*](https://docs.microsoft.com/en-us/visualstudio/test/getting-started-with-unit-testing) which initially fails; once the test passes, you can move on to the next task! +* Pointers to reference materials you might need to solve the tasks, both on quantum computing and on Q#. +* Reference solutions, for when all else fails. + +# Installing and Getting Started # + +To get started with the Quantum Katas, you'll first need to install the [Quantum Development Kit](https://docs.microsoft.com/quantum), available for Windows 10, macOS, and for Linux. +Please see the [install guide for the Quantum Development Kit](https://docs.microsoft.com/en-us/quantum/quantum-installconfig) if you do not already have the Quantum Development Kit installed. + +A quick reference sheet for Q# programming language is available [here](./quickref/qsharp-quick-reference.pdf). + +### Downloading the Quantum Katas ### + +If you have Git installed, go on and clone the Microsoft/QuantumKatas repository. +From your favorite command line: + +```bash +$ git clone https://github.com/Microsoft/QuantumKatas.git +``` + +> **TIP**: Both Visual Studio 2017 and Visual Studio Code make it easy to clone repositories from within your development environment. +> See the [Visual Studio 2017](https://docs.microsoft.com/en-us/vsts/git/tutorial/clone?view=vsts&tabs=visual-studio#clone-from-another-git-provider) and [Visual Studio Code](https://code.visualstudio.com/docs/editor/versioncontrol#_cloning-a-repository) documentation for details. + +Alternatively, if you don't have Git installed, you can manually download a standalone copy of the katas from https://github.com/Microsoft/QuantumKatas/archive/master.zip. + +### Opening a Tutorial ### + +Each individual kata is placed in its own directory as a self-contained Q# solution and project pair. +For instance, the **BasicGates** kata is laid out as below. + +``` +QuantumKatas/ + BasicGates/ + README.md # Instructions specific to this kata. + .vscode/ # Metadata used by Visual Studio Code. + BasicGates.sln # Visual Studio 2017 solution file. + BasicGates.csproj # Project file used to build both classical and quantum code. + + Tasks.qs # Q# source code that you will fill as you solve each task. + Tests.qs # Q# tests that verify your solutions. + TestSuiteRunner.cs # C# source code used to run the Q# tests. + ReferenceImplementation.qs # Q# source code containing solutions to the tasks. +``` + +To open the **BasicGates** kata in Visual Studio 2017, open the `QuantumKatas/BasicGates.sln` solution file. + +To open the **BasicGates** kata in Visual Studio Code, open the `QuantumKatas/BasicGates/` folder. +Press Ctrl + Shift + P / ⌘ + Shift + P to open the Command Palette and type "Open Folder" on Windows 10 or Linux or "Open" on macOS. + +> **TIP**: Almost all commands available in Visual Studio Code can be found in the Command Palette. +> If you ever get stuck, press Ctrl + Shfit + P / ⌘ + Shift + P and type some letters to search through all available commands. + +> **TIP**: You can also launch Visual Studio Code from the command line if you prefer: +> ```bash +> $ code QuantumKatas/BasicGates/ +> ``` + +### Running Kata Tests ### + +Once you have a kata open, it's time to run the tests using the instructions below. +Initially all tests will fail; do not panic! +Open the `Tasks.qs` file and start filling in the code to complete the tasks. Each task is covered by a unit test; once you fill in the correct code for a task, rebuild the project and re-run the tests, and the corresponding unit test will pass. + +#### Visual Studio 2017 + +1. Build solution. +2. Open Test Explorer (found in `Test` > `Windows` menu) and select "Run All" to run all unit tests at once. +3. Work on the tasks in the `Tasks.qs` file. +4. To test your code changes for a task, rebuild solution and re-run all unit tests using "Run All" or the unit test which covers that task by right-clicking on that test and selecting "Run Selected Tests". + +#### Visual Studio Code + +1. Press Ctrl + \` / ⌘ + \` to open the integrated terminal. + The terminal should already start in the kata directory, but if not, use `cd` to navigate to the folder containing the `*.csproj` file for the kata. +2. Run `dotnet test` in the integrated terminal. + This should automatically build the kata project and run all unit tests; initially, all unit tests should fail. +3. Work on the tasks in the `Tasks.qs` file. +4. To test your code changes for a task, run `dotnet test` again. + +For convenience, we also provide a `tasks.json` configuration for each kata that allows Visual Studio Code to run the build and test steps from the Command Palette. +Press Ctrl + Shift + P / ⌘ + Shift + P to open the Palette and type "Run Build Task" or "Run Test Task," then press Enter. # Contributing diff --git a/Superposition/.vscode/extensions.json b/Superposition/.vscode/extensions.json new file mode 100644 index 00000000000..14d152e069a --- /dev/null +++ b/Superposition/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "quantum.quantum-devkit-vscode" + ] +} \ No newline at end of file diff --git a/Superposition/.vscode/tasks.json b/Superposition/.vscode/tasks.json new file mode 100644 index 00000000000..bae788317e9 --- /dev/null +++ b/Superposition/.vscode/tasks.json @@ -0,0 +1,36 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "args": [ + "build" + ], + "type": "process", + "group": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + }, + { + "label": "test", + "command": "dotnet", + "args": [ + "test" + ], + "type": "process", + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Superposition/README.md b/Superposition/README.md new file mode 100644 index 00000000000..c2e8821b15b --- /dev/null +++ b/Superposition/README.md @@ -0,0 +1,12 @@ +# Welcome! + +The superposition kata covers the following topics: + - basic single-qubit and multi-qubit gates + - superposition + - flow control and recursion in Q# + +It is recommended to complete the basic gates kata before this one to get familiar with the basic gates used in quantum computing. The list of basic gates available in Q# can be found at [Microsoft.Quantum.Primitive](https://docs.microsoft.com/en-us/qsharp/api/prelude/microsoft.quantum.primitive). + +You can find detailed coverage of Bell states and their creation [here](https://blogs.msdn.microsoft.com/uk_faculty_connection/2018/02/06/a-beginners-guide-to-quantum-computing-and-q/). + +For the syntax of flow control statements in Q#, see [the Q# documentation](https://docs.microsoft.com/en-us/quantum/quantum-qr-statements#control-flow). diff --git a/Superposition/ReferenceImplementation.qs b/Superposition/ReferenceImplementation.qs new file mode 100644 index 00000000000..f6435225ff5 --- /dev/null +++ b/Superposition/ReferenceImplementation.qs @@ -0,0 +1,320 @@ +// 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.Superposition +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Convert; + open Microsoft.Quantum.Extensions.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[]) : () + { + body + { + H(qs[0]); + } + adjoint auto; + } + + // 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[]) : () + { + body + { + X(qs[0]); + H(qs[0]); + } + adjoint auto; + } + + // Task 3. Unequal superposition + // Inputs: + // 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) : () + { + body + { + // Hint: Experiment with rotation gates from Microsoft.Quantum.Primitive + Ry(2.0 * alpha, qs[0]); + } + adjoint auto; + } + + // Task 4. 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[]) : () + { + body + { + H(qs[0]); + CNOT(qs[0], qs[1]); + } + adjoint auto; + } + + // Task 5. All Bell states + // Inputs: + // 1) two qubits in |00〉 state (stored in an array of length 2) + // 2) an integer index + // Goal: create one of the Bell states based on the value of index: + // 0: |Φ⁺〉 = (|00〉 + |11〉) / sqrt(2) + // 1: |Φ⁻〉 = (|00〉 - |11〉) / sqrt(2) + // 2: |Ψ⁺〉 = (|01〉 + |10〉) / sqrt(2) + // 3: |Ψ⁻〉 = (|01〉 - |10〉) / sqrt(2) + operation AllBellStates_Reference (qs : Qubit[], index : Int) : () + { + body + { + 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]); + } + } + adjoint auto; + } + + // Task 6. 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[]) : () + { + body + { + H(qs[0]); + for (i in 1 .. Length(qs)-1) { + CNOT(qs[0], qs[i]); + } + } + adjoint auto; + } + + // Task 7. Superposition of all basis vectors + // 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[]) : () + { + body + { + for (i in 0 .. Length(qs)-1) { + H(qs[i]); + } + } + adjoint auto; + } + + // Task 8. Superposition of |0...0〉 and given bit string + // Inputs: + // 1) N qubits in |0...0〉 state + // 2) bit string represented as Bool[] + // Goal: create an equal superposition of |0...0〉 and basis state given by the second bit string. + // Bit values false and true correspond to |0〉 and |1〉 states. + // 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[]) : () + { + 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"); + + // 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]); + } + } + } + adjoint auto; + } + + // Task 9. Superposition of two bit strings + // Inputs: + // 1) N qubits in |0...0〉 state + // 2) two bit string represented as Bool[]s + // Goal: create an equal superposition of two basis states given by the bit strings. + // Bit values false and true correspond to |0〉 and |1〉 states. + // Example: for bit strings [false; true; false] and [false; false; true] + // the qubit state required is (|010〉 + |001〉) / sqrt(2). + // You are guaranteed that the two bit strings will be different. + + // helper function for TwoBitstringSuperposition_Reference + function FindFirstDiff_Reference (bits1 : Bool[], bits2 : Bool[]) : Int + { + mutable firstDiff = -1; + for (i in 0 .. Length(bits1)-1) { + if (bits1[i] != bits2[i] && firstDiff == -1) { + set firstDiff = i; + } + } + return firstDiff; + } + + operation TwoBitstringSuperposition_Reference (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : () + { + body + { + // 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]); + + // 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]); + } + } + } + } + } + adjoint auto; + } + + // Task 10. W state on 2^k qubits + // Input: N = 2^k qubits in |0...0〉 state. + // 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[]) : () + { + body + { + let N = Length(qs); + 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]); + + // the next K qubits are in |0...0〉 state + // allocate ancilla in |+〉 state + using (anc = Qubit[1]) { + H(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[0]); + } + } + } + } + adjoint auto; + } + + // Task 11. W state on arbitrary number of qubits + // Input: N qubits in |0...0〉 state (N is not necessarily a power of 2). + // 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 = 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[]) : () + { + body + { + 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 WState_Arbitrary_Reference)(qs[0..0], qs[1..N-1]); + X(qs[0]); + } + } + adjoint auto; + controlled auto; + adjoint controlled auto; + } + + // solution based on generation for 2^k and post-selection using measurements + operation WState_Arbitrary_Postselect (qs : Qubit[]) : () + { + body + { + let N = Length(qs); + if (N == 1) { + // base case of recursion: |1〉 + X(qs[0]); + } else { + // find the smallest power of 2 which is greater than or equal to N + // as a hack, we know we're not doing it on more than 64 qubits + mutable P = 1; + for (i in 1..6) { + if (P < N) { + set P = P * 2; + } + } + + if (P == N) { + // prepare as a power of 2 (previous task) + WState_PowerOfTwo_Reference(qs); + } else { + // allocate extra qubits + using (ans = Qubit[P-N]) { + let all_qubits = qs + ans; + repeat { + // prepare state W_P on original + ancilla qubits + WState_PowerOfTwo_Reference(all_qubits); + + // measure ancilla qubits; if all of the results are Zero, we get the right state on main qubits + mutable allZeros = true; + for (i in 0..P-N-1) { + set allZeros = allZeros && IsResultZero(M(ans[i])); + } + } until allZeros + fixup { + ResetAll(ans); + } + } + } + } + } + } +} diff --git a/Superposition/Superposition.csproj b/Superposition/Superposition.csproj new file mode 100644 index 00000000000..64a5599bc0e --- /dev/null +++ b/Superposition/Superposition.csproj @@ -0,0 +1,22 @@ + + + netcoreapp2.0 + x64 + false + Quantum.Kata.Superposition + + + + + + + + + + + + + + + + diff --git a/Superposition/Superposition.sln b/Superposition/Superposition.sln new file mode 100644 index 00000000000..ec25fd63f70 --- /dev/null +++ b/Superposition/Superposition.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Superposition", "Superposition.csproj", "{1FD1C660-6646-44B0-B252-32378CBF682B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1FD1C660-6646-44B0-B252-32378CBF682B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FD1C660-6646-44B0-B252-32378CBF682B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FD1C660-6646-44B0-B252-32378CBF682B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FD1C660-6646-44B0-B252-32378CBF682B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0DE89BFF-6EB5-4848-AB40-A01C1CD406FB} + EndGlobalSection +EndGlobal diff --git a/Superposition/Tasks.qs b/Superposition/Tasks.qs new file mode 100644 index 00000000000..6a0e0e5ab06 --- /dev/null +++ b/Superposition/Tasks.qs @@ -0,0 +1,194 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Quantum.Kata.Superposition +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Convert; + open Microsoft.Quantum.Extensions.Math; + + ////////////////////////////////////////////////////////////////// + // Welcome! + ////////////////////////////////////////////////////////////////// + + // "Superposition" quantum kata is a series of exercises designed + // to get you familiar with programming in Q#. + // It covers the following topics: + // - basic single-qubit and multi-qubit gates, + // - superposition, + // - flow control and recursion in Q#. + // + // 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. + + // 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 (qs : Qubit[]) : () + { + body + { + // Hadamard gate H will convert |0⟩ state to |+⟩ state. + // The first qubit of the array can be accessed as qs[0]. + // Type H(qs[0]); + // Then rebuild the project and rerun the tests - T01_PlusState_Test should now pass! + + // ... + } + } + + // 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 (qs : Qubit[]) : () + { + body + { + // In this task, as well as in all subsequent ones, you have to come up with the solution yourself. + + // ... + } + } + + // Task 3*. Unequal superposition + // Inputs: + // 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 (qs : Qubit[], alpha : Double) : () + { + body + { + // Hint: Experiment with rotation gates from Microsoft.Quantum.Primitive namespace. + // Note that all rotation operators rotate the state by _half_ of its angle argument. + + // ... + } + } + + // Task 4. 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 (qs : Qubit[]) : () + { + body + { + // ... + } + } + + // Task 5. All Bell states + // Inputs: + // 1) two qubits in |00〉 state (stored in an array of length 2) + // 2) an integer index + // Goal: create one of the Bell states based on the value of index: + // 0: |Φ⁺〉 = (|00〉 + |11〉) / sqrt(2) + // 1: |Φ⁻〉 = (|00〉 - |11〉) / sqrt(2) + // 2: |Ψ⁺〉 = (|01〉 + |10〉) / sqrt(2) + // 3: |Ψ⁻〉 = (|01〉 - |10〉) / sqrt(2) + operation AllBellStates (qs : Qubit[], index : Int) : () + { + body + { + // ... + } + } + + // Task 6. 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 (qs : Qubit[]) : () + { + body + { + // Hint: N can be found as Length(qs). + + // ... + } + } + + // Task 7. Superposition of all basis vectors + // 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 (qs : Qubit[]) : () + { + body + { + // ... + } + } + + // Task 8. Superposition of |0...0⟩ and given bit string + // Inputs: + // 1) N qubits in |0...0⟩ state + // 2) bit string represented as Bool[] + // Goal: create an equal superposition of |0...0⟩ and basis state given by the bit string. + // Bit values false and true correspond to |0⟩ and |1⟩ states. + // 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 (qs : Qubit[], bits : Bool[]) : () + { + body + { + // 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"); + + // ... + } + } + + // Task 9. Superposition of two bit strings + // Inputs: + // 1) N qubits in |0...0⟩ state + // 2) two bit string represented as Bool[]s + // Goal: create an equal superposition of two basis states given by the bit strings. + // Bit values false and true correspond to |0⟩ and |1⟩ states. + // Example: for bit strings [false; true; false] and [false; false; true] + // the qubit state required is (|010⟩ + |001⟩) / sqrt(2). + // You are guaranteed that the both bit strings have the same length as the qubit array, + // and that the bit strings will differ in at least one bit. + operation TwoBitstringSuperposition (qs : Qubit[], bits1 : Bool[], bits2 : Bool[]) : () + { + body + { + // ... + } + } + + // Task 10**. W state on 2^k qubits + // Input: N = 2^k qubits in |0...0⟩ state. + // 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 (qs : Qubit[]) : () + { + body + { + // Hint: you can use Controlled functor to perform arbitrary controlled gates. + + // ... + } + } + + // Task 11**. W state on arbitrary number of qubits + // Input: N qubits in |0...0⟩ state (N is not necessarily a power of 2). + // 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 = 3, W state is (|100⟩ + |010⟩ + |001⟩) / sqrt(3). + operation WState_Arbitrary (qs : Qubit[]) : () + { + body + { + // ... + } + } +} diff --git a/Superposition/TestSuiteRunner.cs b/Superposition/TestSuiteRunner.cs new file mode 100644 index 00000000000..e31251f2cb9 --- /dev/null +++ b/Superposition/TestSuiteRunner.cs @@ -0,0 +1,42 @@ +// 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 Microsoft.Quantum.Simulation.Simulators; +using Xunit.Abstractions; +using System.Diagnostics; + +namespace Quantum.Kata.Superposition +{ + public class TestSuiteRunner + { + private readonly ITestOutputHelper output; + + public TestSuiteRunner(ITestOutputHelper output) + { + this.output = output; + } + + /// + /// This driver will run all Q# tests (operations named "...Test") + /// that belong to namespace Quantum.Kata.Superposition. + /// + [OperationDriver(TestNamespace = "Quantum.Kata.Superposition")] + public void TestTarget(TestOperation op) + { + using (var sim = new QuantumSimulator()) + { + // 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); + } + } + } +} diff --git a/Superposition/Tests.qs b/Superposition/Tests.qs new file mode 100644 index 00000000000..38b505e319b --- /dev/null +++ b/Superposition/Tests.qs @@ -0,0 +1,240 @@ +// 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.Superposition +{ + open Microsoft.Quantum.Primitive; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Extensions.Convert; + open Microsoft.Quantum.Extensions.Math; + open Microsoft.Quantum.Extensions.Testing; + + // ------------------------------------------------------ + operation AssertEqualOnZeroState (N : Int, testImpl : (Qubit[] => ()), refImpl : (Qubit[] => () : Adjoint)) : () + { + body + { + using (qs = Qubit[N]) + { + // apply operation that needs to be tested + testImpl(qs); + + // apply adjoint reference operation and check that the result is |0〉 + (Adjoint refImpl)(qs); + + // assert that all qubits end up in |0〉 state + AssertAllZero(qs); + } + } + } + + // ------------------------------------------------------ + operation T01_PlusState_Test () : () + { + body + { + AssertEqualOnZeroState(1, PlusState, PlusState_Reference); + } + } + + // ------------------------------------------------------ + operation T02_MinusState_Test () : () + { + body + { + AssertEqualOnZeroState(1, MinusState, MinusState_Reference); + } + } + + // ------------------------------------------------------ + operation T03_UnequalSuperposition_Test () : () + { + body + { + // cross-test + AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.0), ApplyToEachA(I, _)); + AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.5 * PI()), ApplyToEachA(X, _)); + AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.5 * PI()), ApplyToEachA(Y, _)); + AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.25 * PI()), PlusState_Reference); + AssertEqualOnZeroState(1, UnequalSuperposition(_, 0.75 * PI()), MinusState_Reference); + + for (i in 1..36) { + let alpha = 2.0 * PI() * ToDouble(i) / 36.0; + AssertEqualOnZeroState(1, UnequalSuperposition(_, alpha), UnequalSuperposition_Reference(_, alpha)); + } + } + } + + // ------------------------------------------------------ + operation T04_BellState_Test () : () + { + body + { + AssertEqualOnZeroState(2, BellState, BellState_Reference); + } + } + + // ------------------------------------------------------ + operation T05_AllBellStates_Test () : () + { + body + { + for (i in 0..3) { + AssertEqualOnZeroState(2, AllBellStates(_, i), AllBellStates_Reference(_, i)); + } + } + } + + // ------------------------------------------------------ + operation T06_GHZ_State_Test () : () + { + body + { + // for N = 1 it's just |+〉 + AssertEqualOnZeroState(1, GHZ_State, PlusState_Reference); + // for N = 2 it's Bell state + AssertEqualOnZeroState(2, GHZ_State, BellState_Reference); + for (n in 3..9) { + AssertEqualOnZeroState(n, GHZ_State, GHZ_State_Reference); + } + } + } + + // ------------------------------------------------------ + operation T07_AllBasisVectorsSuperposition_Test () : () + { + body + { + // for N = 1 it's just |+〉 + AssertEqualOnZeroState(1, AllBasisVectorsSuperposition, PlusState_Reference); + + for (n in 2..9) { + AssertEqualOnZeroState(n, AllBasisVectorsSuperposition, AllBasisVectorsSuperposition_Reference); + } + } + } + + // ------------------------------------------------------ + operation T08_ZeroAndBitstringSuperposition_Test () : () + { + body + { + // compare with results of previous operations + AssertEqualOnZeroState(1, ZeroAndBitstringSuperposition(_, [true]), PlusState_Reference); + AssertEqualOnZeroState(2, ZeroAndBitstringSuperposition(_, [true; true]), BellState_Reference); + AssertEqualOnZeroState(3, ZeroAndBitstringSuperposition(_, [true; true; true]), GHZ_State_Reference); + + if (true) { + let b = [true; false]; + AssertEqualOnZeroState(2, ZeroAndBitstringSuperposition(_, b), + ZeroAndBitstringSuperposition_Reference(_, b)); + } + if (true) { + let b = [true; false; true]; + AssertEqualOnZeroState(3, ZeroAndBitstringSuperposition(_, b), + ZeroAndBitstringSuperposition_Reference(_, b)); + } + if (true) { + let b = [true; false; true; true; false; false]; + AssertEqualOnZeroState(6, ZeroAndBitstringSuperposition(_, b), + ZeroAndBitstringSuperposition_Reference(_, b)); + } + } + } + + // ------------------------------------------------------ + operation T09_TwoBitstringSuperposition_Test () : () + { + body + { + // compare with results of previous operations + AssertEqualOnZeroState(1, TwoBitstringSuperposition(_, [true], [false]), PlusState_Reference); + AssertEqualOnZeroState(2, TwoBitstringSuperposition(_, [false; false], [true; true]), BellState_Reference); + AssertEqualOnZeroState(3, TwoBitstringSuperposition(_, [true; true; true], [false; false; false]), GHZ_State_Reference); + + // compare with reference implementation + // diff in first position + for (i in 1..1) + { + let b1 = [false; true]; + let b2 = [true; false]; + AssertEqualOnZeroState(2, TwoBitstringSuperposition(_, b1, b2), + TwoBitstringSuperposition_Reference(_, b1, b2)); + } + for (i in 1..1) + { + let b1 = [true; true; false]; + let b2 = [false; true; true]; + AssertEqualOnZeroState(3, TwoBitstringSuperposition(_, b1, b2), + TwoBitstringSuperposition_Reference(_, b1, b2)); + } + // diff in last position + for (i in 1..1) + { + let b1 = [false; true; true; false]; + let b2 = [false; true; true; true]; + AssertEqualOnZeroState(4, TwoBitstringSuperposition(_, b1, b2), + TwoBitstringSuperposition_Reference(_, b1, b2)); + } + // diff in the middle + for (i in 1..1) + { + let b1 = [true; false; false; false]; + let b2 = [true; false; true; true]; + AssertEqualOnZeroState(4, TwoBitstringSuperposition(_, b1, b2), + TwoBitstringSuperposition_Reference(_, b1, b2)); + } + } + } + + // ------------------------------------------------------ + operation T10_WState_PowerOfTwo_Test () : () + { + body + { + // separate check for N = 1 (return must be |1〉) + using (qs = Qubit[1]) { + WState_PowerOfTwo(qs); + Assert([PauliZ], qs, One, ""); + X(qs[0]); + } + + AssertEqualOnZeroState(2, WState_PowerOfTwo, TwoBitstringSuperposition_Reference(_, [false; true], [true; false])); + AssertEqualOnZeroState(4, WState_PowerOfTwo, WState_PowerOfTwo_Reference); + AssertEqualOnZeroState(8, WState_PowerOfTwo, WState_PowerOfTwo_Reference); + AssertEqualOnZeroState(16, WState_PowerOfTwo, WState_PowerOfTwo_Reference); + } + } + + // ------------------------------------------------------ + operation T11_WState_Arbitrary_Test () : () + { + body + { + // separate check for N = 1 (return must be |1〉) + using (qs = Qubit[1]) { + WState_Arbitrary_Reference(qs); + Assert([PauliZ], qs, One, ""); + X(qs[0]); + } + + // cross-tests + AssertEqualOnZeroState(2, WState_Arbitrary, TwoBitstringSuperposition_Reference(_, [false; true], [true; false])); + + AssertEqualOnZeroState(2, WState_Arbitrary, WState_PowerOfTwo_Reference); + AssertEqualOnZeroState(4, WState_Arbitrary, WState_PowerOfTwo_Reference); + AssertEqualOnZeroState(8, WState_Arbitrary, WState_PowerOfTwo_Reference); + AssertEqualOnZeroState(16, WState_Arbitrary, WState_PowerOfTwo_Reference); + + for (i in 2..16) { + AssertEqualOnZeroState(i, WState_Arbitrary, WState_Arbitrary_Reference); + } + } + } +} \ No newline at end of file diff --git a/quickref/qsharp-quick-reference.pdf b/quickref/qsharp-quick-reference.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6e06b8a1d0de4d5c59a7751a79946464060dace2 GIT binary patch literal 73056 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∾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 z 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 LrK;-c@5TiHy4Y5h literal 0 HcmV?d00001 diff --git a/quickref/qsharp-quick-reference.tex b/quickref/qsharp-quick-reference.tex new file mode 100644 index 00000000000..e0afa775907 --- /dev/null +++ b/quickref/qsharp-quick-reference.tex @@ -0,0 +1,262 @@ +% Copyright (c) Microsoft Corporation. All rights reserved. +% Licensed under the MIT License. + +%!TEX program=xelatex +% This cheatsheet is based on the template +% provided at https://gist.github.com/alexander-yakushev/c773543bf9a957749f79. +\documentclass[10pt,english,landscape]{article} +\usepackage{multicol} +\usepackage{calc} +\usepackage[landscape]{geometry} +\usepackage{color,graphicx,overpic} + +% https://tex.stackexchange.com/a/192067 +\usepackage{fontawesome} + \newfontfamily{\FA}{[FontAwesome.otf]} + +% Known issue in {fontspec}: https://github.com/wspr/fontspec/issues/312#issuecomment-342125206 +% Since {fontspec} is included only when compiling with XeTeX, we guard +% our fix accordingly. +\usepackage{ifxetex} + \ifxetex + \let\latinencoding\relax + \usepackage{fontspec} + \setmainfont{Segoe UI} + \setmonofont{Consolas} + \fi + +% \usepackage[T1]{fontenc} +% \usepackage[bitstream-charter]{mathdesign} +\usepackage[utf8]{inputenc} +\usepackage{url} +\usepackage{amsfonts} +\usepackage{array,booktabs} +\usepackage{textcomp} +\usepackage[usenames,dvipsnames,table]{xcolor} +\usepackage[most]{tcolorbox} +\usepackage{menukeys} +\usepackage{tabularx} +\usepackage{multirow} +\usepackage{colortbl} +\usepackage{tikz} +\usepackage{environ} +\usepackage{braket} + +\usetikzlibrary{calc} +\pgfdeclarelayer{background} +\pgfdeclarelayer{foreground} +\pgfsetlayers{background,main,foreground} + +\geometry{top=-0.5cm,left=1cm,right=1cm,bottom=1cm} + +\pagestyle{empty} % Turn off header and footer + +% \renewcommand\rmdefault{phv} % Arial +% \renewcommand\sfdefault{phv} % Arial + +% Redefine section commands to use less space +\makeatletter +\renewcommand{\section}{\@startsection{section}{1}{0mm}% + {-1ex plus -.5ex minus -.2ex}% + {0.5ex plus .2ex}%x + {\normalfont\large\bfseries}} +\renewcommand{\subsection}{\@startsection{subsection}{2}{0mm}% + {-1explus -.5ex minus -.2ex}% + {0.5ex plus .2ex}% + {\normalfont\normalsize\bfseries}} +\renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{0mm}% + {-1ex plus -.5ex minus -.2ex}% + {1ex plus .2ex}% + {\normalfont\small\bfseries}} +\makeatother + +\setcounter{secnumdepth}{0} % Don't print section numbers +\setlength{\parindent}{0pt} +\setlength{\parskip}{0pt plus 0.5ex} + +\definecolor{TableHead}{rgb}{0.353, 0.329, 0.667} +\definecolor{TableRow}{rgb}{0.816, 0.812, 0.902} + +\NewEnviron{keysref}[1]{ + % \begin{center} + \smallskip + \begin{tikzpicture} + \rowcolors{1}{}{TableRow} + + \node (tbl) [inner sep=0pt] { + \begin{tabular}{p{2.5cm}p{5.05cm}} + \rowcolor{TableHead} + \multicolumn{2}{l}{\normalsize\textbf{\color{white}{#1}}}\parbox{0pt}{\rule{0pt}{0.3ex+\baselineskip}}\\ + \BODY + \arrayrulecolor{TableHead}\specialrule{.17em}{0em}{.2em} + \end{tabular}}; + \begin{pgfonlayer}{background} + \draw[rounded corners=2pt,top color=TableHead,bottom color=TableHead, draw=white] + ($(tbl.north west)-(0,-0.05)$) rectangle ($(tbl.north east)-(0.0,0.15)$); + \draw[rounded corners=2pt,top color=TableHead,bottom color=TableHead, draw=white] + ($(tbl.south west)-(0.0,-0.11)$) rectangle ($(tbl.south east)-(-0.0,-0.02)$); + \end{pgfonlayer} + \end{tikzpicture} + % \end{center} +} + +% https://tex.stackexchange.com/a/102523 +\newcommand{\forceindent}[1]{\leavevmode{\parindent=#1\indent}} + +%% CUSTOM NOTATION %% + +\newcommand{\qs}{Q\#} +\newcommand{\unixlike}{\hfill\faApple\faLinux} +\newcommand{\ctrllike}{\hfill\faWindows\faLinux} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{document} + +\raggedright\ + +% \begin{center} + \Large{\qs~Language Quick Reference} +% \end{center} + +\footnotesize +\begin{multicols}{3} + + \begin{keysref}{Primitive Types} + 64-bit integers & \texttt{Int} \\ + Double-precision floats & \texttt{Double} \\ + Booleans & \texttt{Bool} \newline + e.g.: \texttt{true} or \texttt{false} \\ + Qubits & \texttt{Qubit} \\ + Pauli basis & \texttt{Pauli} \newline + e.g.: \texttt{PauliI}, \texttt{PauliX}, \texttt{PauliY}, or \texttt{PauliZ} \\ + Measurement \newline results & \texttt{Result} \newline + e.g.: \texttt{Zero} or \texttt{One} \\ + Sequences of \newline integers & \texttt{Range} \newline + e.g.: 1..10 or 5..-1..0 \\ + Strings & \texttt{String} \\ + \end{keysref} + + \begin{keysref}{Derived Types} + Arrays & \texttt{\emph{elementType}[]} \\ + Tuples & \texttt{(\emph{type0}, \emph{type1}, ...)} \newline + e.g.: \texttt{(Int, Qubit)} \\ + Functions & \texttt{\emph{input} -> \emph{output}} \newline + e.g.: \texttt{ArcTan2 : (Double, Double) -> Double} \\ + Operations & \texttt{\emph{input} => \emph{output} : \emph{variants}} \newline + e.g.: \texttt{H : (Qubit => () : Adjoint, Controlled)} \\ + \end{keysref} + + \begin{keysref}{Functions, Operations and Types} + Define function \newline (classical routine) + & \texttt{function \emph{Name}(\emph{in0} : \emph{type0}, ...) : \emph{returnType} \{} \newline + \texttt{\hphantom{....}// \emph{function body}} \newline + \texttt{\}} \\ + Define operation \newline (quantum routine) + & \texttt{operation \emph{Name}(\emph{in0} : \emph{type0}, ...) : \emph{returnType} \{} \newline + \texttt{\hphantom{....}body \{ ... \}} \newline + \texttt{\hphantom{....}adjoint \{ ... \}} \newline + \texttt{\hphantom{....}controlled \{ ... \}} \newline + \texttt{\hphantom{....}adjoint controlled \{ ... \}} \newline + \texttt{\}} \\ + Define \newline user-defined type & \texttt{newtype \emph{TypeName} = \emph{BaseType}} \newline + \texttt{newtype TermList = (Int, Int -> (Double, Double))} \\ + Call adjoint \newline operation & \texttt{(Adjoint \emph{Name})(\emph{parameters})} \\ + Call controlled \newline operation & \texttt{(Controlled \emph{Name})(\emph{controlQubits}, \emph{parameters})} \\ + \end{keysref} + + \begin{keysref}{Symbols and Variables} + Declare immutable \newline symbol & \texttt{let \emph{name} = \emph{value}} \\ + Declare mutable \newline symbol (variable) & \texttt{mutable \emph{name} = \emph{value}} \\ + Update mutable \newline symbol (variable) & \texttt{set \emph{name} = \emph{value}} \\ + \end{keysref} + + \columnbreak%\ + + \begin{keysref}{Arrays} + Allocation & \texttt{mutable \emph{name} = new \emph{Type}[\emph{length}]} \\ + Length & \texttt{Length(\emph{name})} \\ + k-th element & \texttt{\emph{name}[k]} \newline NB: indices are 0-based \\ + Array literal & \texttt{[\emph{value0}; \emph{value1}; ...]} \newline + e.g.: \texttt{[true; false; true]} \\ + Slicing (subarray) & \texttt{let \emph{name} = \emph{name}[\emph{start}..\emph{end}]} \\ + \end{keysref} + + \begin{keysref}{Control Flow} + For loop & \texttt{for (\emph{ind} in \emph{range}) \{ ... \}} \newline + e.g.: \texttt{for (i in 0..N-1) \{ ... \}} \\ + Repeat-until-success loop & \texttt{repeat \{ ... \} \newline until \emph{condition} \newline fixup \{ ... \}} \\ + Conditional \newline statement & \texttt{if \emph{cond1} \{ ... \} \newline elif \emph{cond2} \{ ... \} \newline else \{ ... \}}\\ + Return a value & \texttt{return \emph{value}} \\ + Stop with an error & \texttt{fail "\emph{Error message}"} \\ + \end{keysref} + + \begin{keysref}{Debugging} + Print a string & \texttt{Message("Hello Quantum!")} \\ + Print an \newline interpolated string + & \texttt{Message(\$"Value = \{\emph{val}\}")} \\ + Assert that qubit is in $\ket{0}$ or $\ket{1}$ & \texttt{AssertQubit (expected : Result, q : Qubit)}\\ + Print amplitudes \newline of wave function & \texttt{DumpMachine()} \\ + \end{keysref} + + \begin{keysref}{Qubits and Operations on Qubits} + Allocate qubits & \texttt{using (\emph{name} = Qubit[\emph{length}]) \{} \newline + \texttt{\hphantom{....}//} Qubits in \texttt{\emph{name}} start in $\ket{0}$. \newline + \texttt{\hphantom{....}...} \newline + \texttt{\hphantom{....}//} Qubits must be returned to $\ket{0}$. \newline + \texttt{\}} \\ + Pauli gates & \texttt{X} : + $\ket{0} \mapsto \ket{1}$, $\ket{1} \mapsto \ket{0}$ \newline + \texttt{Y} : + $\ket{0} \mapsto i \ket{1}$, $\ket{1} \mapsto -i \ket{0}$ \newline + \texttt{Z} : + $\ket{0} \mapsto \ket{0}$, $\ket{1} \mapsto -\ket{1}$ \\ + Hadamard & \texttt{H} : + $\ket{0} \mapsto \ket{+} = \frac{1}{\sqrt{2}} ( \ket{0} + \ket{1} )$, \newline + $\ket{1} \mapsto \ket{-} = \frac{1}{\sqrt{2}} ( \ket{0} - \ket{1} )$ \\ + Controlled-NOT & \texttt{CNOT : ((control : Qubit, \newline target : Qubit) => ())} \newline + $\ket{00} \mapsto \ket{00}$, $\ket{01} \mapsto \ket{01}$, \newline + $\ket{10} \mapsto \ket{11}$, $\ket{11} \mapsto \ket{10}$ \\ + Measure qubit in Pauli $Z$ basis & \texttt{M : Qubit => Result} \\ + Perform joint measurement of qubits in given Pauli bases & \texttt{Measure : (Pauli[], Qubit[]) => Result} \\ + Rotate about given Pauli axis & \texttt{R : (Pauli, Double, Qubit) => ()} \\ + Rotate about Pauli $X$, $Y$, $Z$ axis & \texttt{Rx : (Double, Qubit) => ()} \newline + \texttt{Ry : (Double, Qubit) => ()} \newline + \texttt{Rz : (Double, Qubit) => ()} \\ + Reset qubit to $\ket{0}$ & \texttt{Reset : Qubit => ()} \\ + Reset qubits to $\ket{0..0}$ & \texttt{ResetAll : Qubit[] => ()} \\ + \end{keysref} + + \columnbreak%\ + + \section{Resources} + + \begin{keysref}{Documentation} + Quantum \newline Development Kit & \url{https://docs.microsoft.com/quantum} \\ + \qs~Language \newline Reference & \url{https://docs.microsoft.com/quantum/quantum-qr-intro} \\ + \qs~Library \newline Reference & \url{https://docs.microsoft.com/qsharp/api} \\ + \end{keysref} + + \begin{keysref}{\qs~Code Repositories} + QDK Samples and Libraries & \url{https://github.com/Microsoft/Quantum} \\ + Quantum Katas & \url{https://github.com/Microsoft/QuantumKatas} \\ + \end{keysref} + + \begin{keysref}{Command Line Basics} + Change directory & \texttt{cd \emph{dirname}} \\ + Go to home & \texttt{cd \textasciitilde} \\ + Go up one directory & \texttt{cd ..} \\ + Make new directory & \texttt{mkdir \emph{dirname}} \\ + Open current \newline directory in VS Code & \texttt{code .} \\ + \end{keysref} + + \begin{keysref}{Working with \qs~Projects} + Create new project & \texttt{dotnet new console -lang Q\# --output \emph{project-dir}} \\ + Change directory to \newline project directory & \texttt{cd \emph{project-dir}} \\ + Build project & \texttt{dotnet build} \\ + Run all unit tests & \texttt{dotnet test} \\ + \end{keysref} + +\end{multicols} + +\end{document} \ No newline at end of file