From 17fef66830849ddf046ffd33dd8facca8ca4dafb Mon Sep 17 00:00:00 2001 From: Delbert Murphy Date: Thu, 30 Jul 2020 15:38:36 -0400 Subject: [PATCH 1/2] Hackathon: Baseline for new Kata on Functional Programming Techniques --- .../.vscode/extensions.json | 7 + .../.vscode/tasks.json | 36 +++++ .../FunctionalProgrammingTechniques.csproj | 20 +++ .../FunctionalProgrammingTechniques.sln | 25 ++++ FunctionalProgrammingTechniques/README.md | 11 ++ .../ReferenceImplementation.qs | 44 ++++++ FunctionalProgrammingTechniques/Tasks.qs | 133 ++++++++++++++++++ .../TestSuiteRunner.cs | 42 ++++++ FunctionalProgrammingTechniques/Tests.qs | 61 ++++++++ 9 files changed, 379 insertions(+) create mode 100644 FunctionalProgrammingTechniques/.vscode/extensions.json create mode 100644 FunctionalProgrammingTechniques/.vscode/tasks.json create mode 100644 FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.csproj create mode 100644 FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.sln create mode 100644 FunctionalProgrammingTechniques/README.md create mode 100644 FunctionalProgrammingTechniques/ReferenceImplementation.qs create mode 100644 FunctionalProgrammingTechniques/Tasks.qs create mode 100644 FunctionalProgrammingTechniques/TestSuiteRunner.cs create mode 100644 FunctionalProgrammingTechniques/Tests.qs diff --git a/FunctionalProgrammingTechniques/.vscode/extensions.json b/FunctionalProgrammingTechniques/.vscode/extensions.json new file mode 100644 index 00000000000..14d152e069a --- /dev/null +++ b/FunctionalProgrammingTechniques/.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/FunctionalProgrammingTechniques/.vscode/tasks.json b/FunctionalProgrammingTechniques/.vscode/tasks.json new file mode 100644 index 00000000000..bae788317e9 --- /dev/null +++ b/FunctionalProgrammingTechniques/.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/FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.csproj b/FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.csproj new file mode 100644 index 00000000000..97dab042ec7 --- /dev/null +++ b/FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.csproj @@ -0,0 +1,20 @@ + + + netcoreapp3.1 + x64 + false + Quantum.Kata.BasicGates + + + + + + + + + + + + + + diff --git a/FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.sln b/FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.sln new file mode 100644 index 00000000000..1a14381fe93 --- /dev/null +++ b/FunctionalProgrammingTechniques/FunctionalProgrammingTechniques.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30320.27 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalProgrammingTechniques", "FunctionalProgrammingTechniques.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/FunctionalProgrammingTechniques/README.md b/FunctionalProgrammingTechniques/README.md new file mode 100644 index 00000000000..d6f5af815bb --- /dev/null +++ b/FunctionalProgrammingTechniques/README.md @@ -0,0 +1,11 @@ +# Welcome! + +The Functional Programming Techniques kata begins by covering the basics of using functional programming in Q# using classical operations and then adds Quantum operations to that foundation. + +#### Theory + +* + +#### Q# materials + +* \ No newline at end of file diff --git a/FunctionalProgrammingTechniques/ReferenceImplementation.qs b/FunctionalProgrammingTechniques/ReferenceImplementation.qs new file mode 100644 index 00000000000..b5daa978eb9 --- /dev/null +++ b/FunctionalProgrammingTechniques/ReferenceImplementation.qs @@ -0,0 +1,44 @@ +// 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.FunctionalProgrammingTechniques { + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Math; + + //TODO: copy in comments + + function SimpleAdder_Reference ( addend: Int ) : Int { + return Add7 ( addend ); + } + + function Fold_Sum_Reference ( xs: Double[] ) : Double { + return Fold ( Sum, 0.0, xs ); + } + + function Fold_Product_Reference ( xs: Double[] ) : Double { + return Fold( Product, 1.0, xs); + } + + function ComposeImpl_Reference( outerfn: (Double -> Double), innerfn: ( (Int, Int) -> Double ), fractionPiNumerator: Int, fractionPiDenominator: Int ) : Double { + return outerfn(innerfn(fractionPiNumerator, fractionPiDenominator)); + } + + function Compose_Reference(outerfn: (Double -> Double), innerfn: ( (Int, Int) -> Double )) : ( (Int, Int) -> Double ) { + return ComposeImpl_Reference(outerfn, innerfn, _, _); + } + + function Compose_Functions_Reference (fractionPiNumerator: Int, fractionPiDenominator: Int) : Double { + let FractionPi_to_Degrees_Reference = Compose_Reference(Radians_to_Degrees, FractionPi_to_Radians); + return FractionPi_to_Degrees_Reference(fractionPiNumerator, fractionPiDenominator); + } + +} diff --git a/FunctionalProgrammingTechniques/Tasks.qs b/FunctionalProgrammingTechniques/Tasks.qs new file mode 100644 index 00000000000..4d424ee14b6 --- /dev/null +++ b/FunctionalProgrammingTechniques/Tasks.qs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Quantum.Kata.FunctionalProgrammingTechniques { + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Math; + + ////////////////////////////////////////////////////////////////// + // Welcome! + ////////////////////////////////////////////////////////////////// + //TODO: write up intro + + + + ////////////////////////////////////////////////////////////////// + // Part I. Classical Functional Techniques in Q# + ////////////////////////////////////////////////////////////////// + + //Additional function for Task 1.1 + function Add7 ( addend: Int ) : Int { + return addend + 7; + } + + // Task 1.1. Functions as first-class citizens + // Input: An Integer + // Goal: Add 7 to the input Integer, by using the adder variable, defined below. + // The adder variable is assigned to the Add7 function, defined above. + // + // Hint: For this first task, all you have to do is comment out the current return statement + // and uncomment the statement below it. + function SimpleAdder ( addend: Int ) : Int { + let adder = Add7; + + return addend; + //return adder(addend); + } + + + //Additional functions for Task 1.2 and 1.3 + function Sum ( a: Double , b: Double) : Double { + return a + b; + } + + function Product ( a: Double , b: Double) : Double { + return a * b; + } + + // Task 1.2. Higher-Order Functions: Fold (Sum) + // Input: An Array of Double + // Goal: Sum all of the elements of the input Array, without expicitly enumerating them. You can use the Sum + // function above to help you with this task. + // + // This is a common task in Functional programming, so much so that non-functional languages have also encorpated + // this capability. + // This higher-order function is often called Fold (see: https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29 ) + // In the Q# Library, under the Microsoft.Quantum.Arrays namespace you will also find documentation on a Fold function. + // (see: https://docs.microsoft.com/en-us/qsharp/api/qsharp/microsoft.quantum.arrays.fold ) + // + function Fold_Sum ( xs: Double[] ) : Double { + // ... + + return 0.0; + } + + + // Task 1.3. Higher-Order Functions: Fold (Product) + // Input: An Array of Double + // Goal: Multiply all of the elements of the input Array togather, without expicitly enumerating them. You can use the Product + // function above to help you with this task. + // + function Fold_Product ( xs: Double[] ) : Double { + // ... + + return 0.0; + } + + + //Additional functions for Task 1.4 + function FractionPi_to_Radians ( fractionPiNumerator: Int , fractionPiDenominator: Int ) : Double { + return IntAsDouble(fractionPiNumerator) * PI() / IntAsDouble(fractionPiDenominator); + } + + function Radians_to_Degrees ( radians: Double ) : Double { + return radians * 180.0 / PI(); + } + + function ComposeImpl ( outerfn: (Double -> Double), innerfn: ( (Int, Int) -> Double ), fractionPiNumerator: Int, fractionPiDenominator: Int ) : Double { + return outerfn(innerfn(fractionPiNumerator, fractionPiDenominator)); + } + + function DummyFn(dummyvar1: Int, dummyvar2: Int) : Double { + return 0.0; + } + + function Compose ( outerfn: (Double -> Double), innerfn: ( (Int, Int) -> Double )) : ( (Int, Int) -> Double ) { + // ... + return DummyFn; + } + + + // Task 1.4. Composing Functions and Partial Function Application + // Input: Two Integers which represent the numerator and denominator of a fraction of Pi for an angle. For 3Pi/2 the inputs would be 3 and 2, respectively + // Goal: You are provided a function that maps from the numerator and denominator of a fraction of Pi (the measure of an angle) to Radians. You are also provided + // a function that maps from Radians to Degrees. The goal is to compose those functions together, into a function which takes the fractional components and + // converts them to Degrees. The main function below is written for you, as well. Your task is to write the Compose function, by calling the ComposeImpl function. + // + // For a general discussion of Partial Function Application from a computer-science theoretical perspective, see: https://en.wikipedia.org/wiki/Partial_application. + // For details on Q# function composition, see: https://docs.microsoft.com/en-us/quantum/user-guide/using-qsharp/operations-functions + // + function Compose_Functions (fractionPiNumerator: Int, fractionPiDenominator: Int) : Double { + let FractionPi_to_Degrees = Compose(Radians_to_Degrees, FractionPi_to_Radians); + return FractionPi_to_Degrees(fractionPiNumerator, fractionPiDenominator); + } + + + + + ////////////////////////////////////////////////////////////////// + // Part II. Quantum Functional Techniques in Q# + ////////////////////////////////////////////////////////////////// + + + // Task 2.1. Creating a Uniform Superposition on a Register of Qubits + + // Task 2.2. Operating on Multiple Pairs of Qubits in a Register of Qubits + + // Task 2.3. Assembling Parts of the Deutsch-Jozsa Algorithm from Oracles (Functions) + + // Task 2.4. Other Feats of Strength from Quantum Blog Post on Q# + +} diff --git a/FunctionalProgrammingTechniques/TestSuiteRunner.cs b/FunctionalProgrammingTechniques/TestSuiteRunner.cs new file mode 100644 index 00000000000..efbfe26056c --- /dev/null +++ b/FunctionalProgrammingTechniques/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.FunctionalProgrammingTechniques +{ + 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.FunctionalProgrammingTechniques")] + 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/FunctionalProgrammingTechniques/Tests.qs b/FunctionalProgrammingTechniques/Tests.qs new file mode 100644 index 00000000000..76fdf404660 --- /dev/null +++ b/FunctionalProgrammingTechniques/Tests.qs @@ -0,0 +1,61 @@ +// 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.FunctionalProgrammingTechniques { + + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Diagnostics; + + function T101_SimpleAdder_Test () : Unit { + for ( i in 0..7) { + EqualityFactI( SimpleAdder(i), SimpleAdder_Reference(i), "error" ); + } + } + + function T102_Fold_Sum_Test () : Unit { + let tests = [ [ 42.0 , 12.0, 13.0, 17.0 ], + [ 77.0, 3.0, 7.0, 10.0, 20.0, 30.0 ] + ]; + + for ( xs in tests) { + NearEqualityFactD(Fold_Sum_Reference(xs), Fold_Sum(xs)); + } + } + + function T103_Fold_Product_Test () : Unit { + let tests = [ [ 2.0 , 4.0, 6.0 ], + [ 3.0, 5.0 ] + ]; + + for ( xs in tests) { + if (Fold_Product(xs) == 0.0) { + Message("Be sure to check the Input state parameter to your Fold"); + } + + NearEqualityFactD(Fold_Product_Reference(xs), Fold_Product(xs)); + } + } + + function T104_Compose_Functions_Test () : Unit { + let tests = [ [ 1, 2], + [1, 1], + [3, 2], + [2, 1] + ]; + + for ( fraction in tests ) { + NearEqualityFactD(Compose_Functions_Reference(fraction[0], fraction[1]), Compose_Functions(fraction[0], fraction[1])) ; + } + } + +} From cd4275d4fa056ff8cfafee31352062ed43d5f411 Mon Sep 17 00:00:00 2001 From: Delbert Murphy Date: Tue, 4 Aug 2020 19:30:33 -0400 Subject: [PATCH 2/2] What i hope is a code complete first iteration of the Functional Programming Techniques Kata --- FunctionalProgrammingTechniques/README.md | 7 +- .../ReferenceImplementation.qs | 24 ++++ FunctionalProgrammingTechniques/Tasks.qs | 123 +++++++++++++++++- FunctionalProgrammingTechniques/Tests.qs | 58 ++++++++- 4 files changed, 199 insertions(+), 13 deletions(-) diff --git a/FunctionalProgrammingTechniques/README.md b/FunctionalProgrammingTechniques/README.md index d6f5af815bb..12e58146491 100644 --- a/FunctionalProgrammingTechniques/README.md +++ b/FunctionalProgrammingTechniques/README.md @@ -4,8 +4,11 @@ The Functional Programming Techniques kata begins by covering the basics of usin #### Theory -* +* The general theory behind functional programming can be found here: https://en.wikipedia.org/wiki/Functional_programming +* A tremendous introduction to the mathematics behind Category Theory and how Category Theory informs Functional Programming, see: https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/ #### Q# materials -* \ No newline at end of file +* For Q#, the first thing to learn about functions is how they are manifest in Q# as either Functions for Operations: https://docs.microsoft.com/en-us/quantum/user-guide/using-qsharp/operations-functions +* Since Operations are intended for Quantum uses, they also support the Functors Controlled and Adjoint: https://docs.microsoft.com/en-us/quantum/user-guide/using-qsharp/operations-functions#controlled-and-adjoint-operations +* The next step is to understand how the higher-order functions are utilitized in the Quantum Libraries: https://docs.microsoft.com/en-us/quantum/user-guide/libraries/standard/control-flow diff --git a/FunctionalProgrammingTechniques/ReferenceImplementation.qs b/FunctionalProgrammingTechniques/ReferenceImplementation.qs index b5daa978eb9..8ea3a0aba7e 100644 --- a/FunctionalProgrammingTechniques/ReferenceImplementation.qs +++ b/FunctionalProgrammingTechniques/ReferenceImplementation.qs @@ -41,4 +41,28 @@ namespace Quantum.Kata.FunctionalProgrammingTechniques { return FractionPi_to_Degrees_Reference(fractionPiNumerator, fractionPiDenominator); } + operation Uniform_Superposition_Reference ( qs: Qubit[] ) : Unit is Adj + Ctl { + ApplyToEachCA(H, qs); + } + + operation Multiple_CNOT_Reference(qs: Qubit[]) : Unit is Adj + Ctl { + let nQubits = Length(qs); + ApplyToEachCA(CNOT, Zip(qs[0..nQubits -2], qs[1..nQubits - 1])); + } + + operation IsConstantZeroConstant_Reference() : Bool { + return(IsOracleConstant(ConstantZero_Oracle)); + } + + operation IsConstantOneConstant_Reference() : Bool { + return(IsOracleConstant(ConstantOne_Oracle)); + } + + operation IsIdentityConstant_Reference() : Bool { + return(IsOracleConstant(Identity_Oracle)); + } + + operation IsNegationConstant_Reference() : Bool { + return(IsOracleConstant(Negation_Oracle)); + } } diff --git a/FunctionalProgrammingTechniques/Tasks.qs b/FunctionalProgrammingTechniques/Tasks.qs index 4d424ee14b6..1a176ef2f89 100644 --- a/FunctionalProgrammingTechniques/Tasks.qs +++ b/FunctionalProgrammingTechniques/Tasks.qs @@ -3,15 +3,20 @@ namespace Quantum.Kata.FunctionalProgrammingTechniques { open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Math; + open Microsoft.Quantum.Measurement; ////////////////////////////////////////////////////////////////// // Welcome! ////////////////////////////////////////////////////////////////// - //TODO: write up intro - + // + // The Tasks below are laid out in two sections: + // one for Classical functional programming (ie, without Qubits) + // and one for Quantum functional programming (ie, with Qubits) + // ////////////////////////////////////////////////////////////////// @@ -115,19 +120,123 @@ namespace Quantum.Kata.FunctionalProgrammingTechniques { } - - ////////////////////////////////////////////////////////////////// // Part II. Quantum Functional Techniques in Q# ////////////////////////////////////////////////////////////////// + // + // As we move into Quantum applications of functional techniques, the Standard Quantum Libararies provide additional support for these techniques. + // A good jumping off point for this capability is here: https://docs.microsoft.com/en-us/quantum/user-guide/libraries/standard/control-flow + // + // Also note that we are moving from functions to operations for our work, where the Conrolled and Adjunct functors begin to play a role. + // For more information, see: https://docs.microsoft.com/en-us/quantum/user-guide/using-qsharp/operations-functions#controlled-and-adjoint-operations + + // Task 2.1. Creating a Uniform Superposition on a register(an Array) of Qubits + // Input: A register of qubits (ie, an Array of qubits that could be any length) + // Goal: Place the register into a uniform superposition + // Hint: You only need one command to accomplish this task + + operation Uniform_Superposition( xs: Qubit[] ) : Unit is Adj + Ctl { + //... + } - // Task 2.1. Creating a Uniform Superposition on a Register of Qubits // Task 2.2. Operating on Multiple Pairs of Qubits in a Register of Qubits + // + // Some quantum algorythms call for a chain of applications of a CNOT gate to a set of qubits. For example, if you have 4 qubits, you may need to apply a + // series of CNOT gates in this fashon: + // CNOT(first_qubit, second_qubit) + // CNOT(second_qubit, third_qubit) + // CNOT(third_qubit, fourth_qubit) + // and the Quantum Standard Libraries assist with this sort of higher-order control flow + // + // Input: A register of qubits (ie, an Array of qubits that could be any length) + // Goal: Apply the CNOT to each successive pair of qubits in the register + // Hint: You can use the Zip command to simplify this task + + operation Multiple_CNOT(qs: Qubit[]) : Unit is Adj + Ctl { + //... + + } + + // Task 2.3. - 2.6 Assembling Parts of the Deutsch-Jozsa Algorithm from Oracles (Functions) + // + // For deeper explaination of the Deutsch-Jozsa Algorithm, you start by reading the introductions for: + // the Quantum Kata tutorial here: ../turorials/ExploringDeutschJozsaAlgorithm/README.md + // and the Quantum Kata here: ../DeutschJozsaAlgorithm/README.md + // + // For the purposes of these next few tasks, we have simplified the implementation to two qubits: one qubit for the input and one qubit to make the Oracle + // reversable (Adjoint). so the function that we are trying to determine is either constant or balanced will be one of these four functions: + // 1. Constant 0: always returning 0 mapping 0 -> 0 and mapping 1 -> 0 + // 2. Constant 1: always returning 1 mapping 0 -> 1 and mapping 1 -> 1 + // 3. Identity: always returning the input unchanged mapping 0 -> 0 and mapping 1 -> 1 + // 4. Negation: always returning the opposite mapping 0 -> 1 and mapping 1 -> 0 + // + // Inputs: The oracle operation and the IsOracleConstant operation below + // Goal: Compose one Oracle operation with the IsOracleConstant operation to complete each Task, to answer the question IsXXXXXXXConstant - // Task 2.3. Assembling Parts of the Deutsch-Jozsa Algorithm from Oracles (Functions) - // Task 2.4. Other Feats of Strength from Quantum Blog Post on Q# + // oracles are the next 4 functions + operation ConstantZero_Oracle(qs: Qubit[]) : Unit is Adj + Ctl { + } + operation ConstantOne_Oracle(qs: Qubit[]) : Unit is Adj + Ctl { + X(qs[1]); + } + + operation Identity_Oracle(qs: Qubit[]) : Unit is Adj + Ctl { + CNOT(qs[0], qs[1]); + } + + operation Negation_Oracle(qs: Qubit[]) : Unit is Adj + Ctl { + CNOT(qs[0], qs[1]); + X(qs[1]); + } + + // this is the core of the DJ algorithm, where the qubits are prepared and then the oracle is applied, qubits are post-processed and then measured + operation IsOracleConstant(oracle: (Qubit[] => Unit )) : Bool { + mutable result = Zero; + + using (qs = Qubit[2]) + { + X(qs[0]); + X(qs[1]); + H(qs[0]); + H(qs[1]); + + oracle(qs); + + H(qs[0]); + H(qs[1]); + + set result = M(qs[0]); + let _ = M(qs[1]); + } + + return One == result; + } + + // Task 2.3. Deutsch-Jozsa Algorithm: determine if Constant Zero oracle is constant or balanced + operation IsConstantZeroConstant() : Bool { + //note: the answer below is wrong, but this will compile + return false; + } + + // Task 2.4. Deutsch-Jozsa Algorithm: determine if Constant One oracle is constant or balanced + operation IsConstantOneConstant() : Bool { + //note: the answer below is wrong, but this will compile + return false; + } + + // Task 2.5. Deutsch-Jozsa Algorithm: determine if Identity oracle is constant or balanced + operation IsIdentityConstant() : Bool { + //note: the answer below is wrong, but this will compile + return true; + } + + // Task 2.6. Deutsch-Jozsa Algorithm: determine if Negation oracle is constant or balanced + operation IsNegationConstant() : Bool { + //note: the answer below is wrong, but this will compile + return true; + } } diff --git a/FunctionalProgrammingTechniques/Tests.qs b/FunctionalProgrammingTechniques/Tests.qs index 76fdf404660..7ab164a1dfd 100644 --- a/FunctionalProgrammingTechniques/Tests.qs +++ b/FunctionalProgrammingTechniques/Tests.qs @@ -18,7 +18,7 @@ namespace Quantum.Kata.FunctionalProgrammingTechniques { function T101_SimpleAdder_Test () : Unit { for ( i in 0..7) { - EqualityFactI( SimpleAdder(i), SimpleAdder_Reference(i), "error" ); + EqualityFactI( SimpleAdder(i), SimpleAdder_Reference(i), "error: incorrect result" ); } } @@ -28,7 +28,7 @@ namespace Quantum.Kata.FunctionalProgrammingTechniques { ]; for ( xs in tests) { - NearEqualityFactD(Fold_Sum_Reference(xs), Fold_Sum(xs)); + NearEqualityFactD(Fold_Sum(xs), Fold_Sum_Reference(xs)); } } @@ -42,7 +42,7 @@ namespace Quantum.Kata.FunctionalProgrammingTechniques { Message("Be sure to check the Input state parameter to your Fold"); } - NearEqualityFactD(Fold_Product_Reference(xs), Fold_Product(xs)); + NearEqualityFactD(Fold_Product(xs), Fold_Product_Reference(xs)); } } @@ -54,8 +54,58 @@ namespace Quantum.Kata.FunctionalProgrammingTechniques { ]; for ( fraction in tests ) { - NearEqualityFactD(Compose_Functions_Reference(fraction[0], fraction[1]), Compose_Functions(fraction[0], fraction[1])) ; + NearEqualityFactD(Compose_Functions(fraction[0], fraction[1]), Compose_Functions_Reference(fraction[0], fraction[1])) ; } } + // ------------------------------------------------------ + // Helper operation to show the difference between the reference solution and the learner's one + operation DumpDiff (N : Int, + testImpl : (Qubit[] => Unit is Adj+Ctl), + refImpl : (Qubit[] => Unit is Adj+Ctl) + ) : Unit { + using (qs = Qubit[N]) { + // Apply the reference solution and show result + refImpl(qs); + Message("The desired state:"); + DumpMachine(); + ResetAll(qs); + + // Apply learner's solution and show result + testImpl(qs); + Message("The actual state:"); + DumpMachine(); + ResetAll(qs); + } + } + + operation T201_Uniform_Superposition_Test () : Unit { + for (N in 3 .. 5) { + DumpDiff(N, Uniform_Superposition, Uniform_Superposition_Reference); + AssertOperationsEqualReferenced(N, Uniform_Superposition, Uniform_Superposition_Reference); + } + } + + operation T202_Multiple_CNOT_Test () : Unit { + for (N in 5 .. 7) { + DumpDiff(N, Multiple_CNOT, Multiple_CNOT_Reference); + AssertOperationsEqualReferenced(N, Multiple_CNOT, Multiple_CNOT_Reference); + } + } + + operation T203_ConstantZero_Test() : Unit { + EqualityFactB(IsConstantZeroConstant(), IsConstantZeroConstant_Reference(), "error: incorrect result"); + } + + operation T204_ConstantOne_Test() : Unit { + EqualityFactB(IsConstantOneConstant(), IsConstantOneConstant_Reference(), "error: incorrect result"); + } + + operation T205_Identity_Test() : Unit { + EqualityFactB(IsIdentityConstant(), IsIdentityConstant_Reference(), "error: incorrect result"); + } + + operation T206_Negation_Test() : Unit { + EqualityFactB(IsNegationConstant(), IsNegationConstant_Reference(), "error: incorrect result"); + } }