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 00000000000..6e06b8a1d0d
Binary files /dev/null and b/quickref/qsharp-quick-reference.pdf differ
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