diff --git a/HiddenShift/.gitignore b/HiddenShift/.gitignore
new file mode 100755
index 00000000000..1b2a32a9ad7
--- /dev/null
+++ b/HiddenShift/.gitignore
@@ -0,0 +1,357 @@
+### Backup files ###
+*.swp
+*~
+
+### Other files ###
+.DS_Store
+.vscode
+
+# Created by https://www.gitignore.io/api/visualstudio
+# Edit at https://www.gitignore.io/?templates=visualstudio
+
+### VisualStudio ###
+## 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
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+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/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.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
+*.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/
+# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
+**/wwwroot/lib/
+
+# 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
+*- Backup*.rdl
+
+# 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 personal settings
+.cr/personal
+
+# 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/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# End of https://www.gitignore.io/api/visualstudio
+
diff --git a/HiddenShift/GaussianElimination.qs b/HiddenShift/GaussianElimination.qs
new file mode 100755
index 00000000000..ca01cf8a87a
--- /dev/null
+++ b/HiddenShift/GaussianElimination.qs
@@ -0,0 +1,152 @@
+namespace Quantum.Kata.HiddenShift
+{
+ open Microsoft.Quantum.Primitive;
+ open Microsoft.Quantum.Canon;
+
+ ///
+ /// Returns an array of bool vectors which together form the basis of the null space.
+ /// The input matrix may have any dimensions >= 1. It must be rectangular (and not jagged).
+ ///
+ /// Example:
+ ///
+ /// let matrix = [
+ /// [1, 0, 0, 0],
+ /// [0, 1, 0, 0]
+ /// ];
+ /// let kernel = KernelMod2(matrix);
+ ///
+ ///
+ /// kernel is [[0, 0, 1, 0], [0, 0, 0, 1]].
+ ///
+ function KernelMod2(matrix: Int[][]) : Int[][] {
+ let reduced = GaussianEliminationMod2(matrix);
+ let rank = QuickRank(reduced);
+ let nullSpaceDims = Length(matrix[0]) - rank;
+
+ mutable resultNumber = 0;
+ mutable result = new Int[][nullSpaceDims];
+ for (reducedCol in 0..Length(reduced[0])-1) {
+ // Find a column with a non-pivot row to take from
+ // If the element to check to see if this column is a pivot is off the end of the matrix,
+ // treat it as if it's a 0
+ if (reducedCol-resultNumber >= Length(reduced) || reduced[reducedCol-resultNumber][reducedCol] != 1) {
+
+ set result[resultNumber] = new Int[Length(matrix[0])];
+
+ mutable skippedRows = 0;
+ for (resultDimension in 0..Length(matrix[0])-1) {
+ if (resultDimension+skippedRows >= Length(reduced) || reduced[resultDimension-skippedRows][resultDimension] != 1) {
+ // Pull from identity matrix. Each of the skipped rows should be an element of the
+ // identity matrix, instead of the reduced matrix
+ set result[resultNumber][resultDimension] = skippedRows == resultNumber ? 1 | 0;
+ set skippedRows = skippedRows + 1;
+ } else {
+ set result[resultNumber][resultDimension] = reduced[resultDimension+skippedRows][reducedCol]; // Pull from result matrix
+ }
+ }
+ set resultNumber = resultNumber + 1;
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Computes the rank of the given matrix.
+ /// The input matrix may have any dimensions >= 1. It must be rectangular (and not jagged).
+ ///
+ /// Example:
+ ///
+ /// let matrix = [
+ /// [1, 1, 0, 0],
+ /// [0, 1, 0, 0],
+ /// [0, 0, 0, 0]
+ /// ];
+ /// let rank = RankMod2(matrix);
+ ///
+ /// rank is now 2.
+ ///
+ function RankMod2(matrix: Int[][]) : Int {
+ return QuickRank(GaussianEliminationMod2(matrix));
+ }
+
+ /// Computes the rank of the given matrix. Assumes the matrix is in row echelon form.
+ /// The input matrix may have any dimensions > 1. It must be rectangular (and not jagged).
+ function QuickRank(matrix: Int[][]) : Int {
+ mutable zeroRows = 0;
+ for (i in 0..Length(matrix)-1) {
+ mutable onlyZeroes = true;
+ for (j in 0..Length(matrix[i])-1) {
+ if (matrix[i][j] != 0) {
+ set onlyZeroes = false;
+ }
+ }
+
+ if (onlyZeroes) {
+ set zeroRows = zeroRows + 1;
+ }
+ }
+ return Length(matrix) - zeroRows;
+ }
+
+ ///
+ /// Returns the result of computing Gaussian elimination on the given matrix.
+ /// Assumes elements of the matrix are in Z2.
+ /// The input matrix may have any dimensions > 1. It must be rectangular (and not jagged).
+ ///
+ /// Example:
+ ///
+ /// let matrix = [
+ /// [1, 0, 1, 1],
+ /// [0, 1, 1, 0]
+ /// ];
+ /// let rowReduced = GaussianEliminationMod2(matrix);
+ ///
+ ///
+ /// rowReduced is:
+ ///
+ /// [
+ /// [0, 0, 1, 0],
+ /// [0, 0, 0, 1]
+ /// ]
+ ///
+ ///
+ function GaussianEliminationMod2(matrix_: Int[][]) : Int[][] {
+ mutable matrix = matrix_;
+ mutable minPivotRow = 0;
+ for (column in 0..Length(matrix[0])-1) {
+ mutable pivotRow = -1;
+ for (row in minPivotRow..Length(matrix)-1) {
+ if (matrix[row][column] == 1 && pivotRow == -1) {
+ set pivotRow = row;
+ // Add the other rows when needed
+ for (i in 0..Length(matrix)-1) {
+ if (matrix[i][column] == 1 && i != row) {
+ set matrix = AddRowsMod2(matrix, row, i);
+ }
+ }
+ }
+ }
+
+ if (pivotRow != -1) {
+ let temp = matrix[minPivotRow];
+ set matrix[minPivotRow] = matrix[pivotRow];
+ set matrix[pivotRow] = temp;
+
+ set minPivotRow = minPivotRow + 1;
+ }
+ }
+
+ return matrix;
+ }
+
+ /// Helper function to add a source row into a destination row
+ /// matrix[destRow] += matrix[srcRow]
+ function AddRowsMod2(matrix_: Int[][], srcRow: Int, destRow: Int) : Int[][] {
+ mutable matrix = matrix_;
+ for (col in 0..Length(matrix[0])-1) {
+ set matrix[destRow][col] = matrix[destRow][col] ^^^ matrix[srcRow][col];
+ }
+ return matrix;
+ }
+}
diff --git a/HiddenShift/GaussianEliminationTestSuite.cs b/HiddenShift/GaussianEliminationTestSuite.cs
new file mode 100755
index 00000000000..9f8afeef980
--- /dev/null
+++ b/HiddenShift/GaussianEliminationTestSuite.cs
@@ -0,0 +1,30 @@
+using Microsoft.Quantum.Simulation.XUnit;
+using Microsoft.Quantum.Simulation.Simulators;
+using Xunit.Abstractions;
+using System.Diagnostics;
+
+namespace Quantum.Kata.HiddenShift
+{
+ public class GaussianEliminationTestSuite
+ {
+ private readonly ITestOutputHelper output;
+
+ public GaussianEliminationTestSuite(ITestOutputHelper output)
+ {
+ this.output = output;
+ }
+
+ // Use another namespace so tests are seperated in VSTest
+ [OperationDriver(TestNamespace = "Quantum.Kata.HiddenShift.GaussianEliminationTests", DisplayName = "Gaussian Elimination")]
+ public void TestGaussianElimination(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/HiddenShift/GaussianEliminationTests.qs b/HiddenShift/GaussianEliminationTests.qs
new file mode 100755
index 00000000000..1e4f85ab623
--- /dev/null
+++ b/HiddenShift/GaussianEliminationTests.qs
@@ -0,0 +1,225 @@
+namespace Quantum.Kata.HiddenShift.GaussianEliminationTests
+{
+ open Microsoft.Quantum.Primitive;
+ open Microsoft.Quantum.Canon;
+ open Quantum.Kata.HiddenShift;
+
+ operation BasicTest () : Unit
+ {
+ let result = GaussianEliminationMod2([
+ [1, 0],
+ [1, 1]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [1, 0],
+ [0, 1]
+ ], "");
+ }
+
+ operation FirstColumnHasZerosTest() : Unit
+ {
+ let result = GaussianEliminationMod2([
+ [0, 1, 1],
+ [0, 0, 1]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [0, 1, 0],
+ [0, 0, 1]
+ ], "");
+ }
+
+ operation MiddleColumnHasZerosTest() : Unit
+ {
+ let result = GaussianEliminationMod2([
+ [1, 0, 1],
+ [0, 0, 1]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [1, 0, 0],
+ [0, 0, 1]
+ ], "");
+ }
+
+ operation TwoIdenticalRowsTest() : Unit
+ {
+ let result = GaussianEliminationMod2([
+ [1, 1, 0],
+ [1, 1, 0],
+ [0, 0, 0]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [1, 1, 0],
+ [0, 0, 0],
+ [0, 0, 0]
+ ], "");
+ }
+
+ operation OnlyFlipIf1Test () : Unit
+ {
+ // In the second column, only one value is 1, so none of the rows should be modified
+ let result = GaussianEliminationMod2([
+ [1, 0, 1, 0],
+ [0, 1, 1, 0],
+ [0, 0, 0, 0]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [1, 0, 1, 0],
+ [0, 1, 1, 0],
+ [0, 0, 0, 0]
+ ], "");
+ }
+
+ operation FlipIf1Test () : Unit
+ {
+ // In the second column, both the first and third rows and added with the second
+ let result = GaussianEliminationMod2([
+ [1, 1, 1, 0],
+ [0, 1, 1, 0],
+ [0, 1, 0, 0]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0]
+ ], "");
+ }
+
+ operation DoSwapsTest() : Unit
+ {
+ // In the second column, both the first and third rows and added with the second
+ let result = GaussianEliminationMod2([
+ [0, 0, 1, 0],
+ [0, 1, 0, 0],
+ [1, 0, 0, 0]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0]
+ ], "");
+ }
+
+ operation EliminateRowTest() : Unit
+ {
+ let result = GaussianEliminationMod2([
+ [0, 0, 1, 0],
+ [0, 1, 0, 0],
+ [0, 1, 0, 0],
+ [1, 0, 0, 0]
+ ]);
+
+ AssertIntMatrixEqual(result, [
+ [1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0],
+ [0, 0, 0, 0]
+ ], "");
+ }
+
+ operation BasicKernelTest() : Unit
+ {
+ let result = KernelMod2([
+ [1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0],
+ [0, 0, 0, 0]
+ ]);
+
+ AssertSubspaceEqual(result, [
+ [0, 0, 0, 1]
+ ], "");
+ }
+
+ operation TrickyKernelTest() : Unit
+ {
+ let result = KernelMod2([
+ [1, 0, 0, 1],
+ [0, 1, 1, 1]
+ ]);
+
+ AssertSubspaceEqual(result, [
+ [1, 1, 0, 1],
+ [0, 1, 1, 0]
+ ], "");
+ }
+
+ operation TwoIdenticalRowsKernelTest() : Unit
+ {
+ let result = KernelMod2([
+ [1, 1, 0],
+ [1, 1, 0],
+ [0, 0, 0]
+ ]);
+
+ AssertSubspaceEqual(result, [
+ [1, 1, 0],
+ [0, 0, 1]
+ ], "");
+ }
+
+ operation NonPivotInMiddleTest() : Unit {
+
+ let result = KernelMod2([
+ [1,0,1,0,0],
+ [0,1,0,0,0],
+ [0,0,0,1,0],
+ [0,0,0,0,1]
+ ]);
+
+ AssertSubspaceEqual(result, [
+ [1, 0, 1, 0, 0]
+ ], "");
+ }
+
+ operation MultipleNonPivotInMiddleTest() : Unit {
+
+ let result = KernelMod2([
+ [1,0,1,0,0],
+ [0,1,0,0,0],
+ [0,0,0,0,1]
+ ]);
+
+ AssertSubspaceEqual(result, [
+ [1, 0, 1, 0, 0],
+ [0, 0, 0, 1, 0]
+ ], "");
+ }
+
+ function AssertIntMatrixEqual(actual: Int[][], expected: Int[][], message: String) : Unit {
+ AssertIntEqual(Length(actual), Length(expected), message);
+ for (i in 0..Length(actual)-1) {
+ AssertBoolEqual(IntVectorEqual(actual[i], expected[i]), true, $"Expected: {expected} Actual: {actual}. {message}");
+ }
+ }
+
+ function AssertSubspaceEqual(actualBasis: Int[][], expectedBasis: Int[][], message: String) : Unit {
+ AssertIntEqual(Length(actualBasis), Length(expectedBasis), message);
+ for (i in 0..Length(actualBasis)-1) {
+ mutable foundMatch = false;
+ for (j in 0..Length(expectedBasis) - 1) {
+ set foundMatch = foundMatch || IntVectorEqual(actualBasis[i], expectedBasis[j]);
+ }
+ AssertBoolEqual(foundMatch, true, $"Expected: {expectedBasis} Actual: {actualBasis}. {message}");
+ }
+ }
+
+ function IntVectorEqual(a: Int[], b: Int[]) : Bool {
+ if (Length(a) != Length(b)) {
+ return false;
+ }
+
+ mutable equal = true;
+ for (i in 0..Length(a)-1) {
+ set equal = equal && a[i] == b[i];
+ }
+
+ return equal;
+ }
+}
diff --git a/HiddenShift/HiddenShift.csproj b/HiddenShift/HiddenShift.csproj
new file mode 100755
index 00000000000..7921f0dca4b
--- /dev/null
+++ b/HiddenShift/HiddenShift.csproj
@@ -0,0 +1,19 @@
+
+
+ netcoreapp2.0
+ x64
+ false
+ false
+ latest
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HiddenShift/HiddenShift.sln b/HiddenShift/HiddenShift.sln
new file mode 100755
index 00000000000..cc4fc24bc95
--- /dev/null
+++ b/HiddenShift/HiddenShift.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.438
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HiddenShift", "HiddenShift.csproj", "{20F82642-A1E2-4159-AFC2-848AD4F4C801}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {20F82642-A1E2-4159-AFC2-848AD4F4C801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20F82642-A1E2-4159-AFC2-848AD4F4C801}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20F82642-A1E2-4159-AFC2-848AD4F4C801}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20F82642-A1E2-4159-AFC2-848AD4F4C801}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {49B39155-036B-4F43-9DE6-95DA9A5FC8CE}
+ EndGlobalSection
+EndGlobal
diff --git a/HiddenShift/Hidden_Shift_Problem.pdf b/HiddenShift/Hidden_Shift_Problem.pdf
new file mode 100755
index 00000000000..d94de5cd2d3
Binary files /dev/null and b/HiddenShift/Hidden_Shift_Problem.pdf differ
diff --git a/HiddenShift/README.md b/HiddenShift/README.md
new file mode 100755
index 00000000000..aada2819aea
--- /dev/null
+++ b/HiddenShift/README.md
@@ -0,0 +1,24 @@
+# Welcome!
+
+This kata covers the Hidden Shift Problem, which concerns determining a hidden shift s for
+boolean bent functions f and g such that g(x) = f(x + s). This is another example of a
+problem that can be solved exponentially faster by a quantum algorithm than any classical
+algorithms.
+
+This Kata consists of three parts. Task 1 concerns implementing bent boolean functions for
+which problem relies upon. Task 2 concerns implementing a deterministic solution to the
+Hidden Shift Problem that makes O(1) oracle calls. Finally, Task 3 concerns implementing
+a reduction of the Hidden Shift Problem to Simon's Algorithm and similar instances of the
+Hidden Subgroup Problem, solving the Hidden Shift Problem in O(n) oracle calls with a
+guaranteed probability of success. Just as in Simon's Algorithm Kata, the classical portion
+of the generalized Hidden Shift Problem Algorithm is already implemented for you. However,
+unlike the Simon's Algorithm Kata, we have included a Gaussian Elimination library in Q#
+along with the Kata, with which users are free to make their own tests. A dedicated test
+suite is provided to validate the Gaussian Elimination functions.
+
+#### Hidden Shift Problem
+* We recommend completing the [Simon's Algorithm Kata](https://github.com/Microsoft/QuantumKatas/tree/master/SimonsAlgorithm)
+before starting on this Kata.
+* We recommend reading [our paper](Hidden_Shift_Problem.pdf), which goes over all the theory
+and algorithms needed for completing the Hidden Shift Problem Kata.
+* For more details on the Hidden Shift Problem, read [Quantum algorithms for highly non-linear Boolean functions](https://arxiv.org/abs/0811.3208) by Martin Roetteler, on which our paper is based on.
diff --git a/HiddenShift/ReferenceImplementation.qs b/HiddenShift/ReferenceImplementation.qs
new file mode 100755
index 00000000000..d560f2bf76f
--- /dev/null
+++ b/HiddenShift/ReferenceImplementation.qs
@@ -0,0 +1,206 @@
+//////////////////////////////////////////////////////////////////////
+// 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.HiddenShift
+{
+
+ open Microsoft.Quantum.Canon;
+ open Microsoft.Quantum.Primitive;
+ open Microsoft.Quantum.Extensions.Diagnostics;
+
+ //--------------------------------------------------------------------
+
+ // Implement the inner product oracle, which is the most basic kind
+ // of bent function.
+ // The dual of the inner product function is itself.
+ operation InnerProductOracle_Reference(x : Qubit[], target : Qubit) : Unit {
+ body (...) {
+ let N = Length(x);
+ AssertBoolEqual(((N % 2) == 0) && (N > 0), true, "The number of input qubits must be even and positive");
+ for (i in 0 .. 2 .. N-1) {
+ CCNOT(x[i], x[i+1], target);
+ }
+ }
+ controlled adjoint auto;
+ controlled auto;
+ adjoint auto;
+ }
+
+ // Implement a quadratic boolean function oracle.
+ // Q is an upper triangular matrix of 0's and 1's with 0's along the diagonal.
+ // L is a row vector of 0's and 1's
+ operation QuadraticOracle_Reference(x : Qubit[], target : Qubit, Q : Int[][], L : Int[]) : Unit {
+ body (...) {
+ let N = Length(x);
+ AssertIntEqual(N, Length(L), "The length of x and L must be equal");
+ AssertIntEqual(N, Length(Q), "The length of x and Q must be equal");
+ AssertIntEqual(Length(Q), Length(Q[0]), "Q must be a square matrix");
+ for (j in 0 .. N-1) {
+ if (L[j] == 1) {
+ CNOT(x[j], target);
+ }
+ for (i in 0 .. j - 1) {
+ if (Q[i][j] == 1) {
+ CCNOT(x[i], x[j], target);
+ }
+ }
+ }
+ }
+ controlled adjoint auto;
+ controlled auto;
+ adjoint auto;
+ }
+
+ //--------------------------------------------------------------------
+
+ operation ShiftedOracle_Helper_Reference(Uf : ((Qubit[], Qubit) => Unit : Adjoint, Controlled), s : Int[], x : Qubit[], target : Qubit) : Unit {
+ body (...) {
+ let N = Length(x);
+ using (qs = Qubit[N]) {
+ for (i in 0 .. N-1) {
+ if (s[i] == 1) {
+ X(qs[i]);
+ }
+ }
+ for (i in 0 .. N - 1) {
+ CNOT(x[i], qs[i]);
+ }
+ Uf(qs, target);
+ for (i in 0 .. N - 1) {
+ CNOT(x[i], qs[i]);
+ }
+ for (i in 0 .. N-1) {
+ if (s[i] == 1) {
+ X(qs[i]);
+ }
+ }
+ }
+ }
+ controlled adjoint auto;
+ controlled auto;
+ adjoint auto;
+ }
+
+ // Returns the shifted oracle g for a marking oracle f such that g(x) = f(x + s).
+ function ShiftedOracle_Reference(Uf : ((Qubit[], Qubit) => Unit : Adjoint, Controlled), s : Int[]) : ((Qubit[], Qubit) => Unit : Adjoint, Controlled) {
+ return ShiftedOracle_Helper_Reference(Uf, s, _, _);
+ }
+
+ operation PhaseFlipOracle_Helper_Reference(Uf : ((Qubit[], Qubit) => Unit : Adjoint, Controlled), x : Qubit[]) : Unit {
+ body (...) {
+ let N = Length(x);
+ using (b = Qubit()) {
+ X(b);
+ H(b);
+ Uf(x, b);
+ H(b);
+ X(b);
+ }
+ }
+ controlled adjoint auto;
+ controlled auto;
+ adjoint auto;
+ }
+
+ // Returns the phase flip oracle corresponding to the marking oracle f.
+ function PhaseFlipOracle_Reference(Uf : ((Qubit[], Qubit) => Unit : Adjoint, Controlled)) : ((Qubit[]) => Unit : Adjoint, Controlled) {
+ return PhaseFlipOracle_Helper_Reference(Uf, _);
+ }
+
+ //--------------------------------------------------------------------
+
+ operation WalshHadamard_Reference (x : Qubit[]) : Unit {
+ body (...) {
+ ApplyToEachA(H, x);
+ }
+ adjoint auto;
+ }
+
+ // Determines the hidden shift s from the oracle for g(x) and the daul of f(x).
+ operation DeterministicHiddenShiftSolution_Reference (N : Int, Ug : ((Qubit[]) => Unit), Ufd : ((Qubit[]) => Unit)) : Int[] {
+ mutable res = new Int[N];
+ using (qs = Qubit[N]) {
+ ApplyToEach(H, qs);
+ Ug(qs);
+ WalshHadamard_Reference(qs);
+ Ufd(qs);
+ WalshHadamard_Reference(qs);
+ for (i in 0 .. N-1) {
+ set res[i] = M(qs[i]) == One ? 1 | 0;
+ }
+ ResetAll(qs);
+ }
+ return res;
+ }
+
+ //--------------------------------------------------------------------
+
+ operation HidingFunctionOracle_Helper_Reference (Uf : ((Qubit[]) => Unit : Adjoint, Controlled), Ug : ((Qubit[]) => Unit : Adjoint, Controlled),
+ b : Qubit, x : Qubit[], target : Qubit[]) : Unit {
+ body (...) {
+ ApplyToEachCA(H, target);
+ for (i in 0 .. Length(x) - 1) {
+ CNOT(x[i], target[i]);
+ }
+
+ Controlled Ug([b], (target));
+ X(b);
+ Controlled Uf([b], (target));
+ X(b);
+
+ for (i in 0 .. Length(x) - 1) {
+ CNOT(x[i], target[i]);
+ }
+ ApplyToEachCA(H, target);
+ }
+ controlled adjoint auto;
+ controlled auto;
+ adjoint auto;
+ }
+
+ function HidingFunctionOracle_Reference (Uf : ((Qubit[]) => Unit : Adjoint, Controlled), Ug : ((Qubit[]) => Unit : Adjoint, Controlled)) :
+ ((Qubit, Qubit[], Qubit[]) => Unit : Adjoint, Controlled) {
+ return HidingFunctionOracle_Helper_Reference(Uf, Ug, _, _, _);
+ }
+
+ operation HiddenShiftIteration_Reference(n: Int, Uf : ((Qubit[]) => Unit : Adjoint, Controlled), Ug : ((Qubit[]) => Unit : Adjoint, Controlled)) : Int[] {
+ mutable result = new Int[n+1];
+
+ using ((cosetReg, targetReg) = (Qubit[n+1], Qubit[n])) {
+ ApplyToEach(H, cosetReg);
+
+ let h = HidingFunctionOracle_Reference(Uf, Ug);
+ h(cosetReg[0], cosetReg[1..Length(cosetReg)-1], targetReg);
+
+ ApplyToEach(H, cosetReg);
+
+ for (i in 0..n) {
+ set result[i] = M(cosetReg[i]) == One ? 1 | 0;
+ }
+
+ ResetAll(cosetReg);
+ ResetAll(targetReg);
+ }
+ return result;
+ }
+
+ operation GeneralizedHiddenShift_Reference(n: Int, Uf : ((Qubit[]) => Unit : Adjoint, Controlled), Ug : ((Qubit[]) => Unit : Adjoint, Controlled)) : Int[] {
+ mutable results = new Int[][n+1];
+ for (i in 0 .. Length(results) - 1) {
+ set results[i] = new Int[n+1];
+ }
+ repeat {
+ let newResult = HiddenShiftIteration_Reference(n, Uf, Ug);
+
+ let currentRank = RankMod2(results);
+ set results[currentRank] = newResult;
+ } until (Length(KernelMod2(results)) == 1)
+ fixup {}
+
+ return (KernelMod2(results))[0];
+ }
+}
diff --git a/HiddenShift/Tasks.qs b/HiddenShift/Tasks.qs
new file mode 100755
index 00000000000..391f3c089d2
--- /dev/null
+++ b/HiddenShift/Tasks.qs
@@ -0,0 +1,220 @@
+namespace Quantum.Kata.HiddenShift
+{
+ open Microsoft.Quantum.Canon;
+ open Microsoft.Quantum.Primitive;
+
+ //////////////////////////////////////////////////////////////////
+ // Welcome!
+ //////////////////////////////////////////////////////////////////
+
+ // "HiddenShiftKata" quantum kata is a series of exercises designed to
+ // guide you in implementing algorithms to solve the Hidden Shift Problem
+ // It covers the following topics:
+ // - bent boolean oracles,
+ // - a correlation based solution to the Hidden Shift Problem,
+ // - a Hidden Subgroup based solution to the Hidden Shift Problem.
+
+ // 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.
+
+ // None of the tasks in Part I require measurement.
+
+ // NOTE: remember that addition on a Z_2 x Z_2 x ... is defined as a bitwise XOR.
+
+ //////////////////////////////////////////////////////////////////
+ // Part I. Bent Boolean Oracles
+ //////////////////////////////////////////////////////////////////
+
+ // Task 1.1: Inner Product Oracle f(x) = \sum_{x in 1..2..i-1} x_{i} x_{i+1}
+ // The binary inner product is the most natural kind of bent function, and
+ // has the property where the dual of the inner product oracle is itself.
+ // Inputs:
+ // 1) N qubits in arbitrary state |x> (input register) (N is even)
+ // 2) a qubit in arbitrary state |target> (output qubit)
+ // Goal: transform state |x>|target> into state |x>|target + f(x)> (+ is addition modulo 2).
+ operation InnerProductOracle(x : Qubit[], target : Qubit) : Unit {
+ body (...) {
+ // ...
+ }
+ controlled adjoint auto;
+ controlled auto;
+ adjoint auto;
+ }
+
+ // Task 1.2: Quadratic Boolean Oracle f(x) = x Q x^T + L x^T
+ // Quadratic boolean functions are bent when the symplectic B = Q + Q^T
+ // has full rank. The dual of a quadratic bent function will then be
+ // a quadratic bent function.
+ // Inputs:
+ // 1) N qubits in arbitrary state |x> (input register) (N is even)
+ // 2) a qubit in arbitrary state |target> (output qubit)
+ // 3) an upper triangular N by N matrix Q with 0s along the diagonal
+ // 4) an N length vector L
+ // Goal: transform state |x>|target> into state |x>|target + f(x)> (+ is addition modulo 2).
+ operation QuadraticOracle(x : Qubit[], target : Qubit, Q : Int[][], L : Int[]) : Unit {
+ body (...) {
+ // ...
+ }
+ controlled adjoint auto;
+ controlled auto;
+ adjoint auto;
+ }
+
+ // Task 1.3: Shifted Oracles
+ // Given a marking oracle f that takes |x>|y> to |x>|y + f(x)>
+ // and a shift s, return a marking oracle that takes |x>|y> to |x>|y + g(x)>
+ // where g(x) = f(x + s).
+ //
+ // This task is used as a setup to the Hidden Shift Problem, but is not part of
+ // the quantum algorithm solution. With it, you should be able to implement
+ // your own tests of your Hidden Shift Problem solutions.
+ //
+ // Inputs:
+ // 1) a marking oracle f
+ // 2) an Int array giving a bit string s in {0, 1}^n, where n is the dimension of the domain of f.
+ // Goal: return an oracle that transforms state |x>|y> into state |x>|y + g(x)>
+ function ShiftedOracle(f : ((Qubit[], Qubit) => Unit : Adjoint, Controlled), s : Int[]) : ((Qubit[], Qubit) => Unit : Adjoint, Controlled) {
+ // ...
+ // This task returns a NoOp so that it compiles. You'll likely
+ // need to return your own operation in order to get this to work.
+ return NoOp<(Qubit[], Qubit)>;
+ }
+
+ // Task 1.4: Phase Flip Oracles
+ // Given a marking oracle f that takes |x>|y> to |x>|y + f(x)>,
+ // return a phase flip oracle that takes |x> to (-1)^f(x) |x>
+ // Inputs:
+ // 1) a marking oracle f
+ // Goal: return an oracle that transforms state |x> into state (-1)^f(x) |x>
+ function PhaseFlipOracle(f : ((Qubit[], Qubit) => Unit : Adjoint, Controlled)) : ((Qubit[]) => Unit : Adjoint, Controlled) {
+ // ...
+ // This task returns a NoOp so that it compiles. You'll likely
+ // need to return your own operation in order to get this to work.
+ return NoOp<(Qubit[])>;
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // Part II. Deterministic Solution to the Hidden Shift Problem
+ //////////////////////////////////////////////////////////////////
+
+ // Task 2.1. Implement the Walsh-Hadamard Transform
+ // Inputs:
+ // 1) N qubits in arbitrary state |x>
+ //
+ // Goal: Transform the state according to the Walsh-Hadamard Transform.
+ // The matrix form of the Walsh-Hadamard transform is given by
+ //
+ // (1/Sqrt(2^n)) Sum_{x, y in {0, 1}^n} (-1)^(x, y) |x> (-1)^g(x)|x⟩, where
+ // x is N-qubit input register and g is a bent boolean function
+ // from N-bit strings into {0, 1}
+ // 3) a quantum operation which implements the oracle |x⟩ -> (-1)^fd(x)|x⟩, where
+ // x is N-qubit input register and fd is the dual of f, which is a bent boolean
+ // function from N-bit strings into {0, 1}
+ //
+ // The function g is guaranteed to satisfy the following property:
+ // there exists some N-bit string s such that for all N-bit strings x we have
+ // g(x) = f(x+s)
+ //
+ // Examples of bent boolean functions are the functions from task 1.1 and 1.2;
+ // In the case of the inner product function, it is its own dual function.
+ //
+ // Output:
+ // The bits string s.
+ operation DeterministicHiddenShiftSolution (N : Int, Ug : ((Qubit[]) => Unit), Ufd : ((Qubit[]) => Unit)) : Int[] {
+
+ // Declare an Int array in which the result will be stored;
+ // the array has to be mutable to allow updating its elements.
+ mutable s = new Int[N];
+
+ // Hint: Produce a uniform superposition on all states;
+ // Apply Ug;
+ // Apply the Walsh transform;
+ // Apply Ufd;
+ // Apply the Walsh transform;
+ // Measure out s.
+ // ...
+
+ return s;
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part III. Hidden Subgroup Based Solution to the Hidden Shift Problem
+ //////////////////////////////////////////////////////////////////
+
+ // Task 3.1. Implementing the oracle for the hidden function in the Hidden Subgroup Problem solution to the Hidden Shift Problem
+ // Inputs:
+ // 1) a quantum operation which implements the oracle |x⟩ -> (-1)^f(x)|x⟩, where
+ // x is N-qubit input register and f is a bent boolean function
+ // from N-bit strings into {0, 1}
+ // 2) a quantum operation which implements the oracle |x⟩ -> (-1)^g(x)|x⟩, where
+ // x is N-qubit input register and g is a bent boolean function
+ // from N-bit strings into {0, 1}
+ //
+ // The function g is guaranteed to satisfy the following property:
+ // there exists some N-bit string s such that for all N-bit strings x we have
+ // g(x) = f(x+s)
+ //
+ // Output:
+ // a quantum operation h on inputs (b : Qubit(), x : Qubit[N], target : Qubit[N]) which computes the following value:
+ // let function k(x) = f(x) if b = 0 or g(x) if b = 1, then we map:
+ // |b⟩|x⟩|0⟩ -> |b⟩|x⟩Sum{(-1)^k(x+y)|y⟩}, where the summation is an equal superposition of every y in Z_2^n
+ function HidingFunctionOracle (Uf : ((Qubit[]) => Unit : Adjoint, Controlled), Ug : ((Qubit[]) => Unit : Adjoint, Controlled)) :
+ ((Qubit, Qubit[], Qubit[]) => Unit : Adjoint, Controlled) {
+
+ // Hint: remember that addition is an order 2 operation--the same circuit operation maps y -> x + y and x + y -> y
+
+ // ...
+
+ return NoOp<(Qubit, Qubit[], Qubit[])>;
+ }
+
+ // Task 3.2. Implementing a single iteration of the Hidden Subgroup Problem solution to the Hidden Shift Problem
+ // Inputs:
+ // 1) the number of qubits in the input register N for the functions f and g
+ // 2) a quantum operation which implements the oracle |x⟩ -> (-1)^f(x)|x⟩, where
+ // x is N-qubit input register and f is a bent boolean function
+ // from N-bit strings into {0, 1}
+ // 3) a quantum operation which implements the oracle |x⟩ -> (-1)^g(x)|x⟩, where
+ // x is N-qubit input register and g is a bent boolean function
+ // from N-bit strings into {0, 1}
+ //
+ // The function g is guaranteed to satisfy the following property:
+ // there exists some N-bit string s such that for all N-bit strings x we have
+ // g(x) = f(x+s)
+ //
+ // Output:
+ // an integer array of length N + 1 with entries in Z_2 that is orthogonal to (1, s)
+ // in Z_2^(N+1), i.e. its dot product with (1, s) is 0
+ //
+ // Note that the whole algorithm will reconstruct the bit string s itself, but the quantum part of the
+ // algorithm will only find some vector orthogonal to the bit string s. The classical post-processing
+ // part is already implemented, so once you implement the quantum part, the tests will pass.
+ operation HiddenShiftIteration(N: Int, Uf : ((Qubit[]) => Unit : Adjoint, Controlled), Ug : ((Qubit[]) => Unit : Adjoint, Controlled)) : Int[] {
+ mutable result = new Int[N+1];
+
+ // Perform the general algorithm for a Hidden Subgroup Problem with hidden function h.
+ // Simply create a equal superposition of all inputs to your hidden function, apply the oracle
+ // for h, uncompute the superposition, then measure the input bits. Remember that the oracle
+ // expects the target register in the |0⟩ in every input state.
+
+ // ...
+
+ // Hint: see the Simon's Algorithm Kata
+
+ return result;
+ }
+}
diff --git a/HiddenShift/TestSuiteRunner.cs b/HiddenShift/TestSuiteRunner.cs
new file mode 100755
index 00000000000..cf8c0d23d7c
--- /dev/null
+++ b/HiddenShift/TestSuiteRunner.cs
@@ -0,0 +1,35 @@
+using Microsoft.Quantum.Simulation.XUnit;
+using Microsoft.Quantum.Simulation.Simulators;
+using Xunit.Abstractions;
+using System.Diagnostics;
+
+namespace Quantum.Kata.HiddenShift
+{
+ 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 HiddenShiftKata.
+ ///
+ /// To execute your tests, just type "dotnet test" from the command line.
+ ///
+ [OperationDriver(TestNamespace = "Quantum.Kata.HiddenShift")]
+ 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/HiddenShift/Tests.qs b/HiddenShift/Tests.qs
new file mode 100755
index 00000000000..b26965d5202
--- /dev/null
+++ b/HiddenShift/Tests.qs
@@ -0,0 +1,320 @@
+namespace Quantum.Kata.HiddenShift
+{
+ open Microsoft.Quantum.Canon;
+ open Microsoft.Quantum.Primitive;
+ open Microsoft.Quantum.Extensions.Testing;
+
+ //--------------------------------------------------------------------
+
+ // We test the InnerProductOracle by testing it on all possible input
+ // states and comparing the results with a classical implementation.
+ function InnerProductClassical (arr : Int[]) : Int {
+ mutable res = 0;
+ for (i in 0 .. 2 .. Length(arr) - 1) {
+ if ((arr[i] == 1) && (arr[i+1] == 1)) {
+ set res = res + 1;
+ }
+ }
+ return res % 2;
+ }
+
+ operation InnerProductOracle_TestCase (arr : Int[]) : Unit {
+ let expected = InnerProductClassical(arr);
+ let N = Length(arr);
+ using ((qs, target) = (Qubit[N], Qubit())) {
+ PrepareQubitRegister(qs, arr);
+ InnerProductOracle(qs, target);
+ if (expected == 1) {
+ X(target);
+ }
+ Adjoint PrepareQubitRegister(qs, arr);
+ AssertAllZero(qs);
+ AssertAllZero([target]);
+ }
+ }
+
+ operation InnerProductOracle_Test () : Unit {
+ for (N in 2 .. 2 .. 10) {
+ IterateThroughCartesianPower(N, 2, InnerProductOracle_TestCase);
+ }
+ }
+
+ //--------------------------------------------------------------------
+
+ // We test the QuadraticOracle by testing it with specific inputs Q and L,
+ // on all possible input states and comparing the results with a classical
+ // implementation.
+ function QuadraticClassical (arr : Int[], Q : Int[][], L : Int[]) : Int {
+ let N = Length(arr);
+ mutable res = 0;
+ for (j in 0 .. N - 1) {
+ set res = res + L[j]*arr[j];
+ for (i in 0 .. j - 1) {
+ set res = res + Q[i][j] * arr[i] * arr[j];
+ }
+ set res = res % 2;
+ }
+ return res;
+ }
+
+ operation QuadraticOracle_TestCase (arr : Int[], Q : Int[][], L : Int[]) : Unit {
+ let expected = QuadraticClassical(arr, Q, L);
+ let N = Length(arr);
+ using ((qs, target) = (Qubit[N], Qubit())) {
+ PrepareQubitRegister(qs, arr);
+ QuadraticOracle(qs, target, Q, L);
+ if (expected == 1) {
+ X(target);
+ }
+ Adjoint PrepareQubitRegister(qs, arr);
+ AssertAllZero(qs);
+ AssertAllZero([target]);
+ }
+ }
+
+ operation QuadraticOracle_Test () : Unit {
+ mutable Q = new Int[][2];
+ set Q[0] = [0, 1];
+ set Q[1] = [0, 0];
+ mutable L = [1, 1];
+ IterateThroughCartesianPower(Length(L), 2, QuadraticOracle_TestCase(_, Q, L));
+
+ set Q = new Int[][4];
+ set Q[0] = [0, 1, 1, 1];
+ set Q[1] = [0, 0, 1, 1];
+ set Q[2] = [0, 0, 0, 1];
+ set Q[3] = [0, 0, 0, 0];
+ set L = [1, 0, 0, 0];
+ IterateThroughCartesianPower(Length(L), 2, QuadraticOracle_TestCase(_, Q, L));
+
+ set Q = new Int[][6];
+ set Q[0] = [0, 1, 1, 1, 1, 1];
+ set Q[1] = [0, 0, 1, 1, 1, 1];
+ set Q[2] = [0, 0, 0, 1, 1, 1];
+ set Q[3] = [0, 0, 0, 0, 1, 1];
+ set Q[4] = [0, 0, 0, 0, 0, 1];
+ set Q[5] = [0, 0, 0, 0, 0, 0];
+ set L = [0, 1, 0, 1, 0, 1];
+ IterateThroughCartesianPower(Length(L), 2, QuadraticOracle_TestCase(_, Q, L));
+ }
+
+ //--------------------------------------------------------------------
+
+ operation ShiftedOracle_TestCase (s : Int[]) : Unit {
+ let f = InnerProductOracle_Reference(_, _);
+ let fshifted = ShiftedOracle(f, s);
+ let expected = ShiftedOracle_Reference(f, s);
+ AssertTwoOraclesAreEqual(Length(s) .. Length(s), fshifted, expected);
+ }
+
+ operation ShiftedOracle_Test () : Unit {
+ for (N in 2 .. 2 .. 6) {
+ IterateThroughCartesianPower(N, 2, ShiftedOracle_TestCase);
+ }
+ }
+
+ //--------------------------------------------------------------------
+
+ operation PhaseFlipOracle_Test () : Unit {
+ let f = InnerProductOracle_Reference(_, _);
+ let fphased = PhaseFlipOracle(f);
+ let expected = PhaseFlipOracle_Reference(f);
+ for (N in 2 .. 2 .. 6) {
+ AssertOperationsEqualReferenced(fphased, expected, N);
+ }
+ }
+
+ //--------------------------------------------------------------------
+
+ operation WalshHadamard_Test () : Unit {
+ for (N in 1 .. 6) {
+ AssertOperationsEqualReferenced(WalshHadamard, WalshHadamard_Reference, N);
+ }
+ }
+
+ operation DeterministicHiddenShiftSolution_TestCase (s : Int[]) : Unit {
+ let N = Length(s);
+ // The choices of f and g are arbitrary for testing purposes.
+ let f = InnerProductOracle_Reference(_, _);
+ let g = ShiftedOracle_Reference(f, s);
+ let phasef = PhaseFlipOracle_Reference(f);
+ let phaseg = PhaseFlipOracle_Reference(g);
+ let res = DeterministicHiddenShiftSolution(N, phaseg, phasef);
+ for (j in 0 .. N-1) {
+ if (not (res[j] == s[j])) {
+ fail $"Got {res}. Expected {s}";
+ }
+ }
+ }
+
+ operation DeterministicHiddenShiftSolution_Test () : Unit {
+ for (N in 2 .. 2 .. 4) {
+ IterateThroughCartesianPower(N, 2, DeterministicHiddenShiftSolution_TestCase);
+ }
+ }
+
+ //--------------------------------------------------------------------
+
+ operation HidingFunctionOracle_TestCase (s : Int[]) : Unit {
+ using (b = Qubit()) {
+ // The choices of f and g are arbitrary for testing purposes.
+ let f = InnerProductOracle_Reference(_, _);
+ let g = ShiftedOracle_Reference(f, s);
+ let hUser = HidingFunctionOracle(PhaseFlipOracle_Reference(f), PhaseFlipOracle_Reference(g));
+ let hRef = HidingFunctionOracle_Reference(PhaseFlipOracle_Reference(f), PhaseFlipOracle_Reference(g));
+ let nqubits = Length(s);
+
+ AssertTwoHidingOraclesAreEqual(nqubits .. nqubits, hUser(b, _, _), hRef(b, _, _));
+ X(b);
+ AssertTwoHidingOraclesAreEqual(nqubits .. nqubits, hUser(b, _, _), hRef(b, _, _));
+ X(b);
+ }
+ }
+
+ operation HidingFunctionOracle_Test () : Unit {
+ for (N in 2 .. 2 .. 4) {
+ IterateThroughCartesianPower(N, 2, HidingFunctionOracle_TestCase);
+ }
+ }
+
+ operation HiddenShiftIteration_TestCase (s : Int[]) : Unit {
+ let N = Length(s);
+ // The choices of f and g are arbitrary for testing purposes.
+ let f = InnerProductOracle_Reference(_, _);
+ let g = ShiftedOracle_Reference(f, s);
+ let phasef = PhaseFlipOracle_Reference(f);
+ let phaseg = PhaseFlipOracle_Reference(g);
+
+ // Verify that HiddenShiftIteration does not return all zeros by trying up to 4 attempts.
+ mutable res = new Int[N];
+ let num_iterations = 4;
+ mutable iterations = num_iterations;
+ repeat {
+ set res = HiddenShiftIteration(N, phasef, phaseg);
+ set iterations = iterations - 1;
+ } until ((iterations == 0) || (QuickRank([res]) == 1))
+ fixup {}
+
+ if (QuickRank([res]) == 0) {
+ fail $"HiddenShiftIteration did not produce a non-zero result in {num_iterations} iterations";
+ }
+
+ mutable sum = res[0];
+ for (i in 1 .. N) {
+ set sum = sum + s[i - 1] * res[i];
+ }
+ if (not (sum % 2 == 0)) {
+ fail $"{res} is not orthogonal to (1, {s})";
+ }
+ }
+
+ // Implements the full Hidden Subgroup Based Hidden Shift Algorithm to produce s.
+ operation GeneralizedHiddenShift(n: Int, Uf : ((Qubit[]) => Unit : Adjoint, Controlled), Ug : ((Qubit[]) => Unit : Adjoint, Controlled)) : Int[] {
+ mutable results = new Int[][n+1];
+ for (i in 0 .. Length(results) - 1) {
+ set results[i] = new Int[n+1];
+ }
+ repeat {
+ let newResult = HiddenShiftIteration(n, Uf, Ug);
+
+ let currentRank = RankMod2(results);
+ set results[currentRank] = newResult;
+ } until (Length(KernelMod2(results)) == 1)
+ fixup {}
+
+ return (KernelMod2(results))[0];
+ }
+
+ operation GeneralizedHiddenShift_TestCase (s : Int[]) : Unit {
+ let f = InnerProductOracle_Reference(_, _);
+ let g = ShiftedOracle_Reference(f, s);
+ let phasef = PhaseFlipOracle_Reference(f);
+ let phaseg = PhaseFlipOracle_Reference(g);
+
+ let res = (GeneralizedHiddenShift(Length(s), phasef, phaseg))[1 .. Length(s)];
+ for (i in 0 .. Length(s) - 1) {
+ if (not (s[i] == res[i])) {
+ fail $"Got {res}. Expected {s}";
+ }
+ }
+ }
+
+ operation HiddenShiftIteration_Test () : Unit {
+ for (N in 2 .. 2 .. 4) {
+ IterateThroughCartesianPower(N, 2, HiddenShiftIteration_TestCase);
+ }
+ for (N in 2 .. 2 .. 4) {
+ IterateThroughCartesianPower(N, 2, GeneralizedHiddenShift_TestCase);
+ }
+ }
+
+ // Utilities
+ // ------------------------------------------------------
+ operation PrepareQubitRegister (qs : Qubit[], arr : Int[]) : Unit {
+ body (...) {
+ let N = Length(qs);
+ for (i in 0 .. N - 1) {
+ if (arr[i] == 1) {
+ X(qs[i]);
+ }
+ }
+ }
+ adjoint auto;
+ }
+
+ operation ApplyHidingOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit[]) => Unit : Adjoint)) : Unit {
+
+ body (...) {
+ let N = Length(qs)/2;
+ oracle(qs[0 .. N-1], qs[N..2*N-1]);
+ }
+
+ adjoint invert;
+ }
+
+ operation AssertTwoHidingOraclesAreEqual (
+ nQubits : Range,
+ oracle1 : ((Qubit[], Qubit[]) => Unit : Adjoint),
+ oracle2 : ((Qubit[], Qubit[]) => Unit : Adjoint)) : Unit {
+ let sol = ApplyHidingOracleA(_, oracle1);
+ let refSol = ApplyHidingOracleA(_, oracle2);
+
+ for (i in nQubits) {
+ AssertOperationsEqualReferenced(sol, refSol, 2 * i);
+ }
+ }
+
+ // These operations are taken from the DeutschJozsaAlgorithm Kata.
+ operation ApplyOracleA (qs : Qubit[], oracle : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
+
+ body (...) {
+ let N = Length(qs);
+ oracle(qs[0 .. N - 2], qs[N - 1]);
+ }
+
+ adjoint invert;
+ }
+
+ operation ApplyOracleWithOutputArrA (qs : Qubit[], oracle : ((Qubit[], Qubit[]) => Unit : Adjoint), outputSize : Int) : Unit {
+
+ body (...) {
+ let N = Length(qs);
+ oracle(qs[0 .. (N - 1) - outputSize], qs[N - outputSize .. N - 1]);
+ }
+
+ adjoint invert;
+ }
+
+ operation AssertTwoOraclesAreEqual (
+ nQubits : Range,
+ oracle1 : ((Qubit[], Qubit) => Unit : Adjoint),
+ oracle2 : ((Qubit[], Qubit) => Unit : Adjoint)) : Unit {
+ let sol = ApplyOracleA(_, oracle1);
+ let refSol = ApplyOracleA(_, oracle2);
+
+ for (i in nQubits) {
+ AssertOperationsEqualReferenced(sol, refSol, i + 1);
+ }
+ }
+
+}