From 49e8591825eebbb16c467b4291f7a8b7ec07f39b Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Tue, 20 Aug 2019 10:06:19 +0000 Subject: [PATCH 1/8] quantum counting algorithm --- Counting/Counting.csproj | 23 ++++ Counting/Counting.sln | 25 ++++ Counting/README.md | 11 ++ Counting/ReferenceImplementation.qs | 197 ++++++++++++++++++++++++++++ Counting/Tasks.qs | 78 +++++++++++ Counting/TestSuiteRunner.cs | 42 ++++++ Counting/Tests.qs | 54 ++++++++ 7 files changed, 430 insertions(+) create mode 100644 Counting/Counting.csproj create mode 100644 Counting/Counting.sln create mode 100644 Counting/README.md create mode 100644 Counting/ReferenceImplementation.qs create mode 100644 Counting/Tasks.qs create mode 100644 Counting/TestSuiteRunner.cs create mode 100644 Counting/Tests.qs diff --git a/Counting/Counting.csproj b/Counting/Counting.csproj new file mode 100644 index 00000000000..73fc33c211d --- /dev/null +++ b/Counting/Counting.csproj @@ -0,0 +1,23 @@ + + + netcoreapp2.1 + x64 + false + Quantum.Kata.Counting + Counting + + + + + + + + + + + + + + + + diff --git a/Counting/Counting.sln b/Counting/Counting.sln new file mode 100644 index 00000000000..afeba3f998a --- /dev/null +++ b/Counting/Counting.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28729.10 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Counting", "Counting.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/Counting/README.md b/Counting/README.md new file mode 100644 index 00000000000..9a7f9cb5fbf --- /dev/null +++ b/Counting/README.md @@ -0,0 +1,11 @@ +# Welcome! + +The Counting kata covers the quantum counting algorithm, which is based on Grover's search algorithm. +It solves the problem of computing the number of assignments of Boolean input variables +that make a Boolean function (oracle) true. + +#### Theory + +* The tasks follow the explanation from *Quantum Computation and Quantum Information* by Nielsen and Chuang. + In the 10th anniversary edition, this is section 6.3 on pages 261-263. + diff --git a/Counting/ReferenceImplementation.qs b/Counting/ReferenceImplementation.qs new file mode 100644 index 00000000000..870ba585ad8 --- /dev/null +++ b/Counting/ReferenceImplementation.qs @@ -0,0 +1,197 @@ +// 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.Counting { + + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Oracles; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Arithmetic; + open Microsoft.Quantum.Characterization; + + + ////////////////////////////////////////////////////////////////// + // Part I. Oracle for Counting + ////////////////////////////////////////////////////////////////// + + // Task 1.1. The Sprinkler oracle + // Let us consider an example inspired by the sprinkler problem of (Pearl 1988): + // we have three Boolean variable, s, r, w representing respectively propositions + // “the sprinkler was on”, "ıt rained last night” and “the grass is wet”. + // We know that if the sprinkler was on the grass is wet (s → w), + // if it rained last night the grass is wet (r → w) + //and that the the sprinkler being on and rain last night cannot be true at the same time (s, r →). + // Transformed in conjunctive normal formal we obtain formula (¬s ∨ w) ∧ (¬r ∨ w) ∧ (¬s ∨ ¬r) + // Let s,r,w=queryRegister[0],queryRegister[1],queryRegister[2] + operation Oracle_Sprinkler_Reference (queryRegister : Qubit[], target : Qubit, ancilla : Qubit[]) : Unit + { + body (...) { + X(queryRegister[2]); + X(ancilla[0]); + X(ancilla[1]); + X(ancilla[2]); + + CCNOT(queryRegister[0],queryRegister[1],ancilla[0]); + CCNOT(queryRegister[1],queryRegister[2],ancilla[1]); + CCNOT(queryRegister[0],queryRegister[2],ancilla[2]); + (Controlled X)([ancilla[0],ancilla[1],ancilla[2]],target); + CCNOT(queryRegister[0],queryRegister[2],ancilla[2]); + CCNOT(queryRegister[1],queryRegister[2],ancilla[1]); + CCNOT(queryRegister[0],queryRegister[1],ancilla[0]); + + X(ancilla[2]); + X(ancilla[1]); + X(ancilla[0]); + } + adjoint invert; + controlled auto; + controlled adjoint auto; + } + + + + + // Arbitrary bit pattern oracle + operation Oracle_ArbitraryPattern_Reference (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : Unit + is Adj+Ctl { + (ControlledOnBitString(pattern, X))(queryRegister, target); + } + + + // Oracle converter + operation OracleConverterImpl (markingOracle : ((Qubit[], Qubit) => Unit is Adj+Ctl), register : Qubit[]) : Unit + is Adj+Ctl { + + using (target = Qubit()) { + // Put the target into the |-⟩ state + X(target); + H(target); + + // Apply the marking oracle; since the target is in the |-⟩ state, + // flipping the target if the register satisfies the oracle condition will apply a -1 factor to the state + markingOracle(register, target); + + // Put the target back into |0⟩ so we can return it + H(target); + X(target); + } + } + + + function OracleConverter (markingOracle : ((Qubit[], Qubit) => Unit is Adj+Ctl)) : (Qubit[] => Unit is Adj+Ctl) { + return OracleConverterImpl(markingOracle, _); + } + + + ////////////////////////////////////////////////////////////////// + // Part II. The Grover iteration + ////////////////////////////////////////////////////////////////// + + // The Hadamard transform + operation HadamardTransform (register : Qubit[]) : Unit + is Adj+Ctl { + + // ApplyToEachA(H, register); + + // ApplyToEach is a library routine that is equivalent to the following code: + let nQubits = Length(register); + for (idxQubit in 0..nQubits - 1) { + H(register[idxQubit]); + } + } + + + // Conditional phase flip + operation ConditionalPhaseFlip (register : Qubit[]) : Unit { + + body (...) { + // Define a marking oracle which detects an all zero state + let allZerosOracle = Oracle_ArbitraryPattern_Reference(_, _, new Bool[Length(register)]); + + // Convert it into a phase-flip oracle and apply it + let flipOracle = OracleConverter(allZerosOracle); + flipOracle(register); + R(PauliI, 2.0 * PI(), register[0]); + } + + adjoint self; + controlled auto; + controlled adjoint auto; + } + + + + + // The Grover iteration + operation GroverIteration (register : Qubit[], oracle : (Qubit[] => Unit is Adj+Ctl)) : Unit + { + body (...) { + oracle(register); + HadamardTransform(register); + ConditionalPhaseFlip(register); + HadamardTransform(register); + } + adjoint auto; + controlled auto; + controlled adjoint auto; + } + + + ////////////////////////////////////////////////////////////////// + // Part III. Putting it all together: Quantum Counting + ////////////////////////////////////////////////////////////////// + + operation UnitaryPowerImpl (U : (Qubit[] => Unit is Adj+Ctl), power : Int, q : Qubit[]) : Unit { + body (...) { + for (i in 1..power) { + U(q); + } + } + adjoint auto; + controlled auto; + controlled adjoint auto; + } + + operation Counting_Reference() : Double { + mutable phase = -1.0; + let n=4; + using ((reg,phaseRegister,ancilla)=(Qubit[3],Qubit[n],Qubit[3])) + { + // Construct a phase estimation oracle from the unitary + let phaseOracle = OracleConverter(Oracle_Sprinkler_Reference(_,_,ancilla)); + + let oracle = DiscreteOracle(UnitaryPowerImpl(GroverIteration(_, phaseOracle), _, _)); + + + // Allocate qubits to hold the eigenstate of U and the phase in a big endian register + + let phaseRegisterBE = BigEndian(phaseRegister); + // Prepare the eigenstate of U + HadamardTransform(reg); +//should return 0.5 + // Call library + QuantumPhaseEstimation(oracle, reg, phaseRegisterBE); + // Read out the phase + set phase = IntAsDouble(MeasureInteger(BigEndianAsLittleEndian(phaseRegisterBE))) / IntAsDouble(1 <<< (n)); + + ResetAll(reg); + ResetAll(phaseRegister); + } + let angle = PI()*phase; + let res = (PowD(Sin(angle),2.0)); + + return 8.0*res; + } + + +} diff --git a/Counting/Tasks.qs b/Counting/Tasks.qs new file mode 100644 index 00000000000..3f42bd2a12c --- /dev/null +++ b/Counting/Tasks.qs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +namespace Quantum.Kata.Counting { + + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Oracles; + open Microsoft.Quantum.Arithmetic; + open Microsoft.Quantum.Characterization; + + + ////////////////////////////////////////////////////////////////// + // Welcome! + ////////////////////////////////////////////////////////////////// + + // The "Counting" quantum kata is a series of exercises designed + // to get you familiar with Quantum Counting. + // It covers the following topics: + // - writing oracles for counting, + // - performing actual counting. + + // 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. + + // Within each section, tasks are given in approximate order of increasing difficulty; + // harder ones are marked with asterisks. + + + ////////////////////////////////////////////////////////////////// + // Part I. Oracle for Counting + ////////////////////////////////////////////////////////////////// + + // Task 1.1. The Sprinkler oracle + // Let us consider an example inspired by the sprinkler problem of (Pearl 1988): + // we have three Boolean variable, s, r, w representing respectively propositions + // “the sprinkler was on”, "ıt rained last night” and “the grass is wet”. + // We know that if the sprinkler was on the grass is wet (s → w), + // if it rained last night the grass is wet (r → w) + // and that the the sprinkler being on and rain last night cannot be true at the same time (s, r →). + // Transformed in conjunctive normal formal we obtain formula (¬s ∨ w) ∧ (¬r ∨ w) ∧ (¬s ∨ ¬r) + // Let s,r,w=queryRegister[0],queryRegister[1],queryRegister[2] + // Hint: to solve this task you also need to use ancilla qubits + // This formula has 4 models out of 8 possible worlds + + operation Oracle_Sprinkler (queryRegister : Qubit[], target : Qubit, ancilla : Qubit[]) : Unit + { + body (...) { + // ... + } + adjoint invert; + controlled auto; + controlled adjoint auto; + } + + ////////////////////////////////////////////////////////////////// + // Part I. Counting + ////////////////////////////////////////////////////////////////// + // Implement counting using operations from ReferenceImplementation.qs + // - UnitaryPowerImpl, for computing powers of a unitary operation + // - GroverIteration for the Grover operator + // - QuantumPhaseEstimation, for estimating the phase + // Counting should return the number of models, 4 in this case + operation Counting() : Double { + + // .... + return 4.0; + } + + + + +} diff --git a/Counting/TestSuiteRunner.cs b/Counting/TestSuiteRunner.cs new file mode 100644 index 00000000000..7a412664557 --- /dev/null +++ b/Counting/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.GroversAlgorithm +{ + 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.GroversAlgorithm. + /// + [OperationDriver(TestNamespace = "Quantum.Kata.Counting")] + 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/Counting/Tests.qs b/Counting/Tests.qs new file mode 100644 index 00000000000..55713b8e636 --- /dev/null +++ b/Counting/Tests.qs @@ -0,0 +1,54 @@ +// 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.Counting { + + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Math; + + + // ------------------------------------------------------ + // helper wrapper to represent oracle operation on input and output registers as an operation on an array of qubits + operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit, Qubit[]) => Unit is Adj), qs : Qubit[]) : Unit + is Adj { + let reg= Partitioned([3,1],qs); + op(reg[0], reg[1][0], reg[2]); + } + + + // ------------------------------------------------------ + // helper wrapper to test for operation equality on various register sizes + operation AssertRegisterOperationsEqual (testOp : (Qubit[] => Unit), refOp : (Qubit[] => Unit is Adj)) : Unit { + AssertOperationsEqualReferenced(7, testOp, refOp); + + } + + + // ------------------------------------------------------ + + operation T11_Oracle_Sprinkler_Test () : Unit { + let testOp = QubitArrayWrapperOperation(Oracle_Sprinkler, _); + let refOp = QubitArrayWrapperOperation(Oracle_Sprinkler_Reference, _); + AssertRegisterOperationsEqual(testOp, refOp); + } + + + + + // ------------------------------------------------------ + operation T21_Counting_Test () : Unit { + let reference=Counting(); + let actual=4.0; + EqualityWithinToleranceFact(reference,actual,3.0); + } + +} From 397be166d7bd0a3cdf5ce6be12980e94ce5ace24 Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Tue, 20 Aug 2019 13:22:32 +0000 Subject: [PATCH 2/8] jupther notebook (not working) --- Counting/Counting.ipynb | 316 ++++++++++++++++++++++++++++++++++++++++ Counting/sprinkler.png | Bin 0 -> 46985 bytes 2 files changed, 316 insertions(+) create mode 100644 Counting/Counting.ipynb create mode 100644 Counting/sprinkler.png diff --git a/Counting/Counting.ipynb b/Counting/Counting.ipynb new file mode 100644 index 00000000000..cca0d52a735 --- /dev/null +++ b/Counting/Counting.ipynb @@ -0,0 +1,316 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Counting\n", + "\n", + "\n", + "\n", + "The **Quantum Counting** quantum kata is a series of exercises designed\n", + "to get you familiar with quantum counting algorithm.\n", + "\n", + "It covers the following topics:\n", + "\n", + "* writing oracles for counting,\n", + "* performing actual counting.\n", + " \n", + "\n", + "*Reading material:*\n", + "\n", + "* The tasks follow the explanation from *Quantum Computation and Quantum Information* by Nielsen and Chuang.\n", + " In the 10th anniversary edition, this is section 6.3 on pages 261-263.\n", + " \n", + "Each task is wrapped in one operation preceded by the description of the task.\n", + "Your goal is to fill in the blanks (marked with the `// ...` comments)\n", + "with some Q# code that solves the task. To verify your answer, run the cell with Ctrl/⌘+Enter.\n", + "\n", + "Within each section, tasks are given in approximate order of increasing difficulty;\n", + "harder ones are marked with asterisks." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To begin, first prepare this notebook for execution (if you skip this step, you'll get \"Syntax does not match any known patterns\" error when you try to execute Q# code in the next cells):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%package Microsoft.Quantum.Katas::0.8.1907.1701\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> The package versions in the output of the cell above should always match. If you are running the Notebooks locally and the versions do not match, please install the IQ# version that matches the version of the `Microsoft.Quantum.Katas` package.\n", + ">
\n", + "> How to install the right IQ# version\n", + "> For example, if the version of `Microsoft.Quantum.Katas` package above is 0.1.2.3, the installation steps are as follows:\n", + ">\n", + "> 1. Stop the kernel.\n", + "> 2. Uninstall the existing version of IQ#:\n", + "> dotnet tool uninstall microsoft.quantum.iqsharp -g\n", + "> 3. Install the matching version:\n", + "> dotnet tool install microsoft.quantum.iqsharp -g --version 0.1.2.3\n", + "> 4. Reinstall the kernel:\n", + "> dotnet iqsharp install\n", + "> 5. Restart the Notebook.\n", + ">
\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part I. Oracle Counting\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Task 1.1. The Sprinkler oracle\n", + "\n", + "Let us consider an example inspired by the sprinkler problem of (Pearl 1988): \n", + "we have three Boolean variable, $s$, $r$, $w$ representing respectively propositions \n", + "“the sprinkler was on”, \"ıt rained last night” and “the grass is wet”. \n", + "We know that if the sprinkler was on the grass is wet ($s \\to w$), \n", + "if it rained last night the grass is wet ($r \\to w$) \n", + "and that the the sprinkler being on and rain last night cannot be true at the same time ($s, r \\to$).\n", + "Transformed in conjunctive normal formal we obtain formula $(\\neg s \\vee w) \\wedge (\\neg r \\vee w) \\wedge\n", + "(\\neg s \\vee \\neg r)$.\n", + "Let $s,r,w$=`queryRegister[0],queryRegister[1],queryRegister[2]`\n", + "Hint: to solve this task you also need to use ancilla qubits\n", + "This formula has 4 models out of 8 possible worlds.\n", + "\n", + "
\n", + "
\n", + " Need a hint? Click here \n", + " Here is what the circuit looks like\n", + "\n", + "
\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/snippet:(1,26): error QS6104: No namespace with that name exists.\n", + "/snippet:(3,10): error QS6104: No namespace with that name exists.\n", + "/snippet:(14,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(15,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(16,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(17,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(19,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(20,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(21,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(22,17): error QS5022: No identifier with that name exists.\n", + "/snippet:(23,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(24,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(25,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(27,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(28,5): error QS5022: No identifier with that name exists.\n", + "/snippet:(29,5): error QS5022: No identifier with that name exists.\n" + ] + } + ], + "source": [ + "%kata T11_Oracle_Sprinkler_Test \n", + "\n", + "\n", + "operation Oracle_Sprinkler (queryRegister : Qubit[], target : Qubit, ancilla : Qubit[]) : Unit\n", + " { \n", + "\t body (...) {\n", + "\t\t\t\tX(queryRegister[2]);\n", + "\t\t\t\tX(ancilla[0]);\n", + "\t\t\t\tX(ancilla[1]);\n", + "\t\t\t\tX(ancilla[2]);\n", + " \n", + "\t\t\t\tCCNOT(queryRegister[0],queryRegister[1],ancilla[0]);\n", + "\t\t\t\tCCNOT(queryRegister[1],queryRegister[2],ancilla[1]);\n", + "\t\t\t\tCCNOT(queryRegister[0],queryRegister[2],ancilla[2]);\n", + "\t\t\t\t(Controlled X)([ancilla[0],ancilla[1],ancilla[2]],target);\n", + "\t\t\t\tCCNOT(queryRegister[0],queryRegister[2],ancilla[2]);\n", + "\t\t\t\tCCNOT(queryRegister[1],queryRegister[2],ancilla[1]);\n", + "\t\t\t\tCCNOT(queryRegister[0],queryRegister[1],ancilla[0]);\n", + "\n", + "\t\t\t\tX(ancilla[2]);\n", + "\t\t\t\tX(ancilla[1]);\n", + "\t\t\t\tX(ancilla[0]); \n", + " }\n", + "\t\t\tadjoint invert;\n", + "\t\t\tcontrolled auto;\n", + "\t\t\tcontrolled adjoint auto;\n", + " }" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Part II. Counting" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Task 2.1. Implement counting using operations from ReferenceImplementation.qs\n", + "* UnitaryPowerImpl, for computing powers of a unitary operation\n", + "* GroverIteration for the Grover operator\n", + "* QuantumPhaseEstimation, for estimating the phase\n", + "* Counting should return the number of models, 4 in this case\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/snippet:(1,26): error QS6104: No namespace with that name exists.\n", + "/snippet:(7,27): error QS5022: No identifier with that name exists.\n", + "/snippet:(7,43): error QS5022: No identifier with that name exists.\n", + "/snippet:(9,22): error QS5022: No identifier with that name exists.\n", + "/snippet:(9,37): error QS5022: No identifier with that name exists.\n", + "/snippet:(9,54): error QS5022: No identifier with that name exists.\n", + "/snippet:(14,35): error QS5022: No identifier with that name exists.\n", + "/snippet:(16,17): error QS5022: No identifier with that name exists.\n", + "/snippet:(19,13): error QS5022: No identifier with that name exists.\n", + "/snippet:(21,25): error QS5022: No identifier with that name exists.\n", + "/snippet:(21,37): error QS5022: No identifier with that name exists.\n", + "/snippet:(21,52): error QS5022: No identifier with that name exists.\n", + "/snippet:(21,97): error QS5022: No identifier with that name exists.\n", + "/snippet:(23,13): error QS5022: No identifier with that name exists.\n", + "/snippet:(24,13): error QS5022: No identifier with that name exists.\n", + "/snippet:(26,21): error QS5022: No identifier with that name exists.\n", + "/snippet:(27,20): error QS5022: No identifier with that name exists.\n", + "/snippet:(27,25): error QS5022: No identifier with that name exists.\n" + ] + } + ], + "source": [ + " operation Counting() : Double {\n", + " mutable phase = -1.0;\n", + " let n=4;\n", + " using ((reg,phaseRegister,ancilla)=(Qubit[3],Qubit[n],Qubit[3]))\n", + " {\n", + " // Construct a phase estimation oracle from the unitary\n", + " let phaseOracle = OracleConverter(Oracle_Sprinkler_Reference(_,_,ancilla));\n", + "\n", + " let oracle = DiscreteOracle(UnitaryPowerImpl(GroverIteration(_, phaseOracle), _, _));\n", + "\n", + "\n", + " // Allocate qubits to hold the eigenstate of U and the phase in a big endian register \n", + " \n", + " let phaseRegisterBE = BigEndian(phaseRegister);\n", + " // Prepare the eigenstate of U\n", + " HadamardTransform(reg);\n", + "//should return 0.5\n", + " // Call library\n", + " QuantumPhaseEstimation(oracle, reg, phaseRegisterBE);\n", + " // Read out the phase\n", + " set phase = IntAsDouble(MeasureInteger(BigEndianAsLittleEndian(phaseRegisterBE))) / IntAsDouble(1 <<< (n));\n", + "\n", + " ResetAll(reg);\n", + " ResetAll(phaseRegister);\n", + " }\n", + " let angle = PI()*phase;\n", + " let res = (PowD(Sin(angle),2.0));\n", + "\n", + " return 8.0*res;\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Task 3.2. Using Counting \n", + "\n", + "**Goal:** Use your implementation of Counting from Task 2.1 and the oracle from part 1\n", + " to find the number of solutions of the sprinkler problem. This task is not covered by a test and allows you to experiment with running the algorithm.\n", + " \n", + "> This is an open-ended task, and is not covered by a unit test. To run the code, execute the cell with the definition of the `Run_Counting` operation first; if it compiled successfully without any errors, you can run the operation by executing the next cell (`%simulate Run_GroversSearch_Algorithm`).\n", + "\n", + "> Note that this task relies on your implementations of the previous tasks. If you are getting the \"No variable with that name exists.\" error, you might have to execute previous code cells before retrying this task.\n", + "\n", + "
\n", + "
\n", + " Hint #3\n", + " You can use the Message function to output the results.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + " operation Run_Counting() : Unit {\n", + "\n", + "\t\tlet res=Counting();\n", + " Message(DoubleAsString(res));\n", + "\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Invalid operation name: Run_Counting\n" + ] + } + ], + "source": [ + "%simulate Run_Counting" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Q#", + "language": "qsharp", + "name": "iqsharp" + }, + "language_info": { + "file_extension": ".qs", + "mimetype": "text/x-qsharp", + "name": "qsharp", + "version": "0.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Counting/sprinkler.png b/Counting/sprinkler.png new file mode 100644 index 0000000000000000000000000000000000000000..e6e5f7bb6db1eec38a6150d394ebf7aacc7e95c1 GIT binary patch literal 46985 zcmeFYbySp5_dhxoU;rZ0rKpUwAYG$U(kLw@Aky76pddAbIMOjR(jwhmQqnoZ(Cv^j z0|WN~-}krf`mOuly?5Pp*ZTg!dYJP(=bU|ZozLE9pAc1LS>ju?w?H5evD|B^w;<3h zWf16EH_>&V<={=kF7UW&tRO1|IuDBMZ3KSZw12JR1bp(~@=t6j!x(5Jbe2<+CR`-C ze@BFr^qS*MU>J8#b#3RjMs5%69qm3^Serg@_OLg7U}0hc0%?CqjY*)eKflv5{H|W^wm@4 z5mV*k37zx;nti@Ua&I#&hG%-Z9=V+l$NQphy81BU?N`e@&zK~cBF{Rp3N?3Zh8nPY z+t)Wj{7nm|Am>!chTI$KPhMe9_7D4%*Wa3+qrH!J2gnyr1JIkk2nglcz(C}=(c0>2 zl&`=@cW-Pyzwh?5Qj@jgf%6Yg++pt=r2J@)goCB!L=Kl2K-8(R5FVCL?h_TKw4pl*9AU(_HI(=z;%OzR*c$RP<#I; zc%O`f)k9XzN19OV=2V-1$S1dZt$s#L&wf7p>0b5h=cedmfBt@2vv9jR;wwTNBGm5< z8crKd7WoxhCzh7+tczb0I-bcay(RQNCXSR(4C{I0K~zHV%fP7j+aHX@4`^lcY*>%7gf1ih+c_ys~g$#<;6EE zxEBAGG<`UkzrSLs__))>=tF57alV}+ucMDJ^L2`~ve>g2!Fh^r8haU29b6-Hj~xBo z68GGqJx1G)^()N3=Hz5W@bsl0w&P5C9%bn6ZsG&il$ z{(Qb?Lh0&#kzF@b0=7a5IBJ?x%u3*<(v-eJ96Gicf98`4SlQ!LUB_ML!@ATZsJC?{ zb#i&0{HgJPKHw4+arAy-fc zVHcBG%Yq=fs%hbKgTfJ4XALcODx3a^;Vb*yEDrQjAz#qGAMI6j!je#=>SC9Jp$B=E zJb_3Udy=8Uq=4=I>6)(g)1|igT0(Cx`FMlh%-sBy;TK``2F1Nqx zEB4XB?-%2@P()XrQN|rzA-f~5CZF@yQ&7q?TEcC8^94z)_`{&LJ?74@Byat?qO+ym zA@N16-jdy!NLrf%CH?XKB!#R8W&YEV)cX6;FN=+&$2s5Uo14eqki731Uzg+*U47Mf zRq!_Cdux=UE03}z-CByI$xu&TKF6z4^|TCKKN&WdAIg2wCbo}9kU%hHtMs?Yg9obK ze+z4c&<@9_>zEhsg4iT*PkZk%D6kWnRKBiucMIt*H{kNC8JGVWZeAJiH*vKjqfP%% zGOI16CBI4RlgR69zaDAaonQK6-58ub_dD-h{+NhNAsoSODNfj@Lou6YuVFK0wVz-K z>x_Bh1#!L?(Xl->;5n*62oHMp6}J%fqI*-#sbgfkPNN!rii&d0&r_!%I1t)!-LQVS zPiRdUkz}wP!YOl8EZvLE`W1TqflaS*hBPj1(ND?}sg!D(pBVBWUBYtzI=JOc@NCjf~Db z{-920W9SsIR9UWOmGO>N$mW@1?b9LCVHk7s82UO}p{s zl{7bD7L~6mn_jWkUDYRyTbV&clpz~kMmY@IPA+VxQ3P*gB#Bugoz{n}e8tlWkWan} zq-WNAVz?LdUg>eIT9?nONSWohyThi*%7Jy}hMpo32gIj>=vnGncO|^bw<(`ul1!1( zw-6cLh+_qE`(@YEzgf{`zuSIwdb}bvVy7y>|6t5}aVyRLr4h-CXKb;wsyWx*(Jhe~ z>HGVI&z8uWOb%rKUZMW|GTHKz)(wkjQ-3axyJ2bS_t;W8u76e=h-(OH=4ByRc<7LomWugsD2Y^OWfZ_q8jjqb)bN3W(_Xg-&}C zZ-k??pQMjgEv3#!mfmodlhnm2)VQpVzaZ76k%npn%zaN)UH)7Eqow{x@`dw9Y47G9 z7r${u8|tB{<3Xyd>f}}()f^cn7X`CoM?u$k`UTQ7mw(4>rhW=0l!f~ZTXf#_#KkDs zg1k%84u~GdSsDnvBAg7qen|N0WE?rveeZ+hYEc_Yy;E+});&Fl#b;;1>jY`@H4^dG zF1bomfw!$3N*=6PykG#z>Pi`2z8+!V%>HR1=CJ<*Pl-?t^#}W$ms1}x zv~F)>EVvBGa}jO!JAc=&n*7~*p&!H#Hl9^++zAV`ruBJVPq$5rBp71}< z=g*!N2SMx$;RAJedWLcb5uGi9_i?=pq3QMEVE?`y0l|pTl)qewU#@+&*aTTtL5rV# z_>&~eXh|55_9}2^QlF}fo}`BJGo^~T-GHJqQE1t%gZ^haclo{yykHg8kd9aLa|&-a zC}X?+{u7O=E0sZE$XCUw#T(7M?dBi7Ii;ASbrN}}$GWSV#2P0rxkWEV;i!MPh(omh=MRa zmDAab^nTO5-H8>2!a-@oHV##s3=?M$1Ve;qp)aKHDGtG7)UqTT5#lKO><2I^>s!P; z9$S9WSA50!=Ki;Fx~GOhJ_m6j zJ6=+0hEK^3cmp!EU&sxT-E}6c2=p2tjw0XtCX*o?|NII=A<2`}E2Wv*WqZ2(UEnXg zA*tP>GzZ4fR@ykf5Wh^hDG3aT!U)DZfu7 z0^9^^O`p8TlZDonMy_8AD|LL3r=9sUc{GvF#-A#8SgSqtLM4s_;7@fQms) zhj?l7i+?~Gca^VRJfr{jCnoKt@>pbp3@CLayJUn21bTra0;`NiMqRY5w8()#sZhmD zf{VUv50frX`Tsos@A3h?s0oc42{$-MCr6Gpb{W&a;#TAR?|_Pi0roQ>UkJt5@Pt7R zB(TN%am#9iv>?5lD3iPA;B(Cy6 zgct-G(avB84?pV|)WI9k?r(P+XPBc)g@s6|kXKbGJ z({v`EzGjU+V=^+bT*l7F7mwvWm7fI~#qmm=LB-o>%a~G~5#YZG6 zX|K~07j29dOs1CNCNQ$)yx?&YKVPw_=|ijR!%4Y0ZYn<>@9N|_|IxPf6Wb4L?B;23FiPfw1L6#chdNDP)!6`2)? zx=QJAy!_U$rz#T6N_II@J3j}o)S-i7JMib_>FWNGD>+;r(fcRZ2%gAV@iR*LkN4c> za%6ZyY71HC<}aj|q&v(879G<~EvIKQIHMbRDHE!ZGGYgT z@od^`X$idR#5H~=^BH)%Nu8xY{{xuhFv3*PxM1N@@LZV|(eUXT9|qPvBIQg}AHg57 z{O)gEOWsfN>B&zjDT})hl>OK2AUIhoCK;ObWL`#fXU!>TH;&z7% zEeKTgJy2=0f0cDQftQkO5N0418rR88S<=P%N7hCuGQ#7d(T9OtvpI(t9$4B+>tzqW zM!p?}fd-5np1NJ(RJn0j=#W8g!yFo=#>C}C5K?9tZB871Zb`}*(u476$@i63 zA$KgZ5KH;H0clP53)eCd(m`Kv{6|US%vdpeV6XEuGP&n3DZO>xc=*m>@pdqaa5ro6 zdqcjEOO})QR<|3nAvy-Mt?@lY{z?o7?Cwvbk|^zNcl^`FMea(h)w0fv9kJIP&mUhF zAIV5dtGgW$^D|zWgESv=k|Lf@xpu!`wv}0ca0de1=?wi3f@AmvMyupdt}C{7b*j04wwRj1v95R{pp`r{-nI}UX3)_T^PeZQ1NJi!;{b@ZP$$H^3&M2`+$d%;Bay6 zni(@)->mjm(mx=*6Rfzt;!Tn~CH{+s#UDG%?_Thcc+qy zp>=kb8L@?T8_$2Qw4WuZgs&S_IfBrjA)Qthbh<*tmAG!?6;p_TNr5rdg_obd1?98q zB0oMk8y#UK5Z4hC{xdTAfFP<}?5r4FneV%gXoG||yborlmX)F`#c-n<4e*JL5x&_5 z_b$7KTIvhO4+s*7sbKX}w(+PpQ9EJ`f7yP#0281GLLvBF;|B>#p=NW>&Q{wIQt(Tr zj%yrSAnn+-#8+4wMc=1uXF^NV=lCikDE{pV{OZT{dp1qH%7hf(vJC198ua4W2>!Dx zjEW`ouJXWwmFspOTXL=L`breKZS}dvpi93vqK0?dgoa5=9iZH%OjyfCl(^A#w0nxg z9-yX66)v6%f_qRNmjqYlg^lx_*6}_f9&$R3cqt|I0sR$1y9fHWxfnuddA6z*7J(fR zHyF9f7b*Rr9p}u^7O=#u>MfcBBV!sjtQvMVTiG*wb&cx09DaEt+SqioJ)9k>mNrnrtNuM zjH$_bA|>M)uEpy}Aor)085}oE$x7pFdi_qR(A?>Ccxs}_hUj*_m8@hzW@eVb5a@w% zrpLdD>v77P(8M+VX|!QQkeH6x4vxU1qI^Z8O-yhpO)~|>#loaK5^SotD3Q`K(^1^J z$dyu&-d)LMM5*GCb9(Di{!{sOLRf*D)@SR!I$k(um%P5TKVppZ_8TT-ZcImCC-}&I z`mh10d5&z;wqh3^c=b}d#w-nl<9BKItovQ`y$wvF1{S%pOTtWh0nk?2CUIC|Xgc?{ zsbcta`u%aZJJsbxp84wu@La0o37zn$ir9q{-n1^NTJX1*G8l zb8OF*VfBy&q65P z3@c{1gCU*X)XwcpHTp+&x0oii}7=q z?@&u*@>#Sd>SOVRh{XAUDf)Q!hnh1yY6is@%In7}4U5yquU-hS$&`;JsVst`(#SrW z$5-@_-IMcD1N3B^*ua&6V$}~x!})&9M^|RJIpY_fi6oHzQ(p^ZAqxg}+gIE&vh}u^ zd)&;-1`)StM0v)X|0$5F8asIVT+Sps^2gaGBaOvu%Hlhe4)XD(36_t1z2L{px79}m z5B0p<+=jVZ)a5$YZ+3vQj>(H(`dI^DUQ%pu2S(^S6x%_iB zaG^;%@rDoG&u~=iO(bFs0HBQph^=;RFK7SDk(?m3Xs$|mM1e_rA+;>zBTwY=SmUk? zgy3_x-NB-kqDjM}YwNOeAN~%8~d2O^k zl>s0nqvrVvQ=2dA$c;;@;Gun1DC$!2jdoMp!Kns4-ahWjnINVLCTJf&FEPJ&$z=kI zmIU~;T)5|*f8Nvf1$j$%;j5>c+E@H8$h5zmpd~Eq^yi;Lth&*ce<8|$j$bhCXyL=J z|Me^PEE=914&ihXo|9toal7JQ%H3I!3!s;yj5}En25rMA&(8N#vf1dx}^5OK)^*)|REb+N3 zeoeIP0xcFYCs}{>P_)GzlV9dJ%U~ABi}n{!0^tAqGyH%S8-BXK@%|zqS{7q}@8W|W z0sk*O+enrE5WwQ3!Jc&IMRdq;$N;2{1qMB6#P;{Zb@F-+Vh=>Qnc009cqVYw7nGDm z+yA;j>EO1+4o1_ra-VnTvwF@9@IgfZ*9-y$SRf0Z)lRsjFwrYr(BCAw@Zq+#a*c!( zgka8lRWiri&3MTVcmcXgmhDp6k{V21sx3tci-YQ*C&FJI9Nl6RMT;`8@I-b~`Q}sM z*JO?ZzTO8u_tSlxWF4)1@W}XXMpa}x*w^H=j}6Xrn8D_5(qWuUEcgaFOH9BspyK~g}uaTIQ=4CsuhLZk%B?l5xFq2j>*(Fi- z!A#?4pMV_b=(m6#?KX}9F5Gb7V5BmK$v19>twa_?KWi~5&}I3e)f*E@Zh^Z zciGGCJ4Mt0N)BUYW`;>iIj2*RB~wd7kh_rAul;dqgCtuSU|nn)}Y)(481E0o`1_CzNf z&CCnCC?vjg(~^up%IHSlOXfazwIX)y_hp_^fCOSh@_Y}Kau-sq3pehCh% zfF3D1Vt;qPaeic+u$w@n!N|O&=2saX;KTnS_|&J8^2mHlf3b9c#nlY`6riu+l0N^_ zs;x>DB(+SN<2c8{2m~{2(_oA~H0;mGwLlU4Fb%v?!@QIFm7PsH#Rffs+3LfQPNYT_}$hFQ1&mVK1p;*mI zOeMOKj3+oP_?u60U#ol3(kd4Ux?2C`LO0CgV9J}yc3y=ac#v2GX`W1Q>zI#cB~SAP z+~`h;7qUAtXge*KB`6{6w-SmgTePxYzk?47tzGr5sW6Lryh&R=4*QKBt&KB_f#<<42u(`e^8v7{%2vN| zOb?T(fK1SFN>n>=j9t1 z7X))nAkm57==)V_1wJ|Pq_=^5Rz91iU}t|3)r7u_HI8WASXc@=wL(06bspg02x0y; zbJvKw))M?&O(Zu&twm11sV;r|6>-%*u;EPM-eB(<9pN3(xs@7KZcReMhewQoN$)+P zh6+3F+f)nSj zoypU49K9;nQa@elQ@y@dU-$5FkC-(wr#a0(bnyUncq{x^P)j@fFM61^TLJLMGkD=)swl<{oPPPXZJ!NpN)%>0#=k4i>1Ioy@5pxn=Vn2ri$^`*MJ5Vg zn){1BJ^m!U!dB-$cOM>BoPEjFpyCbB2@a<2aB?=T+P8aA-e#3UV=n%#^HNigF6`jS zar<}l=mg0iBAp_r5$UjdSa9&HrD?bR!qQt-B8p8$hT?F(SukSL$5}a;Kh5~kx2_b? zDZ2`umCf}*SA)l;q@*?gs)}9su!t=zL%J(d^glNdf@QfH-Z;H1=!aU z*!NFby!dF)bxu>8I}D!TH9rgl4NOjLqz%Ca1p?K>LeOoVQ6J|QM0d0f4Di~e-NP4T z&I^qbgQ;ZeR;n1ZXK(qlko;Z!Rb|NVbya2jFWrtU*p$g+xRNW4|0AFF8v*D9G#{)i;Nj4DE{=o{U(+K?eH#X9Zy;Uk(7FbImP(dkl$(|-T%_7V6aZksr< z8r-GM?Y(RfY0k?m5kFzGC9Pj~!=e!eIgea)I}I%{x8X)ocUqm&oLivn&P-2fxJAbk zzu>w`z0W;gU$98k30R?-?jp*rVB_xZqu2C9LN#fg3ks3>(T{@Wq~IkPY@97M@R2?o z2cC&RZEwUe86yh>sj5!)R+mQFr_Z0%8%x(i0d=ZHh@k1o64ib+FfeCA0Z0}F5w1e$ z$ifG_PHhrVpg-!DqTea1*LCw~Q4{phuQ=8WdN%2<#OiG8<$5a331K>76S2ox`c?8je2;nL^Ng2Zb#3~%U85TF)_ZqrNQpO1sE0ofjq{y5U4aa zGow@YBsd#@7i9Q)UlrbwvHh8*6X71oGWRicySUNGORewD3-U{kE^_jw`@sTNxJen#gxg@4 zd8H(ngBdtidFlN7T0n5HcNDZkq2ww4X`lrqZ1nRXeyu33iAOWtNMX`KBP^D?Y@=A!9xvuD?}wwG#G zGITWbjlziubX7cItDxe(c!zy?kJ}{gM^V9^D}J7rJAli62BY1h0f~{v-scI`t(B30 zhpKThNyIyw{LFak$d+_HHR@9G;-}K&GZoS$$Te1g`kfHuzN*+|WLFXZ7qroof-jP1 zbXOM2K@!YAT*NpLkCW<*hTXNL;YjM_g_CU@W9d(-ix;3yGUeGH9E^)4m|+jiK>Dpy z;iIjK!ku}cmhMD8Sncul>wzDoPL@?6m$5OutdNJ(iUSj=F5M_c|6Vd!v~l3A*hQ+N z=?yUT2Qn4(^Bt43g~nbLlDlROOe%=eN-+8|3Y7(_h7ven9vnb`vmEjI*A{Cw5KtXt z_%Wo#<6DMLY>E>&X&6&b8*;Q6-0^d85K3E-9Ps$2z)T%=*l3rAq%YXRoJ z_%Ghjkck6I_d*;I3 zN(tnBUfj-7u4~hMcKDsUOty9jb^$L8>dc8jewH_ZZUUYm22xUrj$Y1{suKF!eX}Y9 z@2-JT<$;>FRF@$j;w3BTLX^oUh_~yuZ#^UCCjh;0xfr!4)950y*Hzld`m%R8=&LNg zeFdaSaj`D8T)M^4Sn_4ullum0H9CkJt$cp~?YOMfD~zhiA7y!zo$X8>HDJnnX;+aGd>imrgFm@j6(XF-i0jU5&nW|Wdz>WM3ApwDVJ0zh0vB9J!b4j=y0 zd>zzKWvH#yVLFH_v>y^$UU%CN=4O^R^PiI2;H|+X@9{M(BZxp&f_Ig(4eC0crnJLB zO;j?2`aYw$n(mRvH&V`v?G`0(L?K1eGp@QxgPJRi{_&898b~q#ijb(cP0yX?w)Z3Zzr|5<4y%YiBp&@8Yf%yUB*?;XuzM_~4wUM6Sd_HYVSYI907o~t z#LKdfO$M5fwI~g$unQ#jM@4M#%wCIpxd#&3lPh9nvygejWalSz+tRKS8rpFoateMhZ|eF+ z{vPPEpe^q2S}@(99scRA$J5s*e=U{QcksHsO(}-P%}Yau%jBLLdKg1Ak7;(RJP6BK zhS#V;aJ#YT8h0I{HMVI#_ylSP!A0E916;Y)dupN1CT|5n6!(-{qGiR8(RYJvs;j~} zt11;~n{xek$5b}Xr~#8r{(Ub+c|dcmmE~RLOupX1N}yUQ$(|_i4f@N zB1+}l-O36lxL+0Nm9Ki0zKAb#Ko=RFZTp5nxMy6Ydqg=VdeJIBPqkW%T_O#CTTDV# z@aBc9T999HI8OVJLzRJ{@a?cV-AB#g_ua!Gi&|lju+S9;yFy1l|I7$E!ZcL~MC)LR>Uu0oC2U(Ar`YtL~wHnf= ze^&jq-u@LcFywe>OSqmpbsR6k6K3EHpn~>}gMFlLEmJ*;bq=T>SSPsti>e926ew>b1X|JxfhJk+rf#1D_$9gj#`GkWV==bJpfr{1+HH%lrd@<-eohwIg zihOGSwzZFh8y!G&bD#B@#Hg@ahq&BDqxBUvRq91}3VsE$g)5L*wms;upoJsTUT$>0 zw~FqCO8qwehB%_@RXEH5xYxWYf}n~d4YY8q5OT)rSQ#NdaN=k|@`{^*x4ouUr*-_qMfx3My>rucoWzP#82eCWXK@1+V1pId zDJ!(dxOsK6(>K?!tZfS}m$vDb{!Khj?LXBSxG`@7PnAWN*KsoFd&$9ZZ3CyQ+)Se{ z?`Xz$pUK(iouycUb@M+WHk}|6+P?j|0{qpQKE$9KfMzIGlt>eYfj^?3Lpw|gsIKa^J>GfLo{_L3 zvhKrsDmM4xxZVq~Rh`?W`&qnhL*Q2Hkm;ftHvRQ@kXG>)eS6X9GeK?#|B=YmV4xty zwNQ)J_YRS=`GO<$!zAmp1ZYu?sKj6=9=h2{v0rB+`0a25P)XpN&7NknrhE40^!yfY z#39jMxBQH~3s4a<^B3cDDg;}#jM+Bv>Z;-i?i~OsH$BX zJU-T6GCc3Kctgfl_t66CsawCjXc?E-{2mfW7GzJQG_oa}Rgx$-c(slp_=GBWvQ&Rza~J$h=S-dR1iV?24~9Pg35v+uF#31jgt8rZ|69#k2} z8)C@hwjQEuO<)G*m)_^FhPZ07Cl#FqHNvq3H-CE@cYm;m7xIY z=uJocAzweLa%nOMW1oWHepcmu(-|)kTF_oET@M+DqYA{J5B($=wPwc1ioFc4{jmh( z;CHxYYoCU8I{r#{(xk&d!tosY!MW9AOD)E8vJW^GQCpMI~37` zbS`w?+vXKMKWHov_j$)&fqj$M*&4EIan@cd)Yus}W^TDA#)8fKQZM~nVtkXX_mO|& zHKxm1O$@I!g#u>bXy)6C|66jbPg(nEQ%KA*33=A)pYvmXjAnU$zE^*_=ZAk`!<|&d|tO@M$|!)3P{2w5|9o zW@N`Z=Dg0<`E8=1&!ei>bK~YQ{(kGDY{MiZ%zKAWTfFm^-2KZcrJnCN!?O9#5XsK z%V_<=8Og!hjgni`$Z;#*#c$v5Ib~(xiRAc*{%UB^;QOu^#0z=fxqe7qY^AuhQ_Piw zz{jF8zH1#mF52`TnUcr|L~N2XG3k}s{<7Ve8wZso*x&2lp@r87Hr4{nwb5*57uH#| zob$rqZ-rykposG*h@QiIEmVc@IvKXE>c^eoW&i5g947cIICjkHr$MMhMgw9q!wMYf zt>?hLF*y$U$($5W+9OdtUEQlsX;0i~MiHO1C}2anjTm;y(+Jn!xc{<^7h+xIgPiIf zs32QMtUn?WJgAQ7qLPJ32yHmD+b|gV5WmpB*o53F#&3aA`&VY;5QfZl9;TI7_c)ehSFwUVpoPHVyXj36elGts!Z$GDb zR@>*8&!F+$yQR##V_oFw|ZDKDEM7vwad+-J-CKJ;^a*Wv+VkFJbGMZN!Sw*Ue)$97hL@0b!;F_wtZiLptaJN%bFSf?svIvB z+>G-iwg;6OZ|rOe-6pMgI}bvyOs|%G~|ykPX~ zBE!x(;Iy&jG!YF1sX&>Ry(^v_xmeIx`&+JRb`|$m3*bw9{wUG1jzk~R9*_xVG}$v< zh16gYX()1LLdb>oEe1cg-h$X_6kN@jiLdb~a+};lzudTg?hEF?ze6hFP72h6P^2K%vx+!~(Z}j$WwtFsx?l^RX}t6;YPMb-QRD`$J`_D|092 zH?Z`x&VCzyE}R%EG0Yg}be(MT!Ab(_$x2Z6hW($}4)wF@GZcA^&n9;8#Q%#aSJHn6 zty-(^Uv80ef!pgN9}UG9)pT1%2PH%+j`ZcA_gg7%#}@v4rzMnPq%|wX-V(V}t~r|D z&StOWvl8pM?)Ka2K;=oTilE#L#O8qa$>rv}(lz?C_{w`A-$M0g&SBi$7LZg$YyJbo zD8E)d0lyt^J3yDG4X%?fJt| z`Qjz=gw{`!T)E{-XVCC%4kNgR>hG&Swq-o!lL@$kXY9R(t~GrfJZsfG{LMiIQwApa zDCKF&fFRd(s{A$uWV*a%3SxKYdF|efobz>_x^IPdkM?#`ZP~AU+)e=L9S*p9E(HD^j22He{g-5(2jyz_-fKj_0w>XQKgo{ zaO1m?hzJuAp1tmZ5bt<_!1SB|E{nelI)5JCKI7tsTvy)2d&ZhY#C~j-wsuD67Px5N zD00GPlppGT{2XODa_&^$Ir&@#rcqUo$E1pd2Z{v#V95P~T~Ee-?FKkSnwgX# z^09h4T`_vIHQ^f)IH5eHR2q}>NT0P}KS_4g9*20v8(Qwo|G==Cr8LDCkAtgErE^H~ zo1*9ZJxixG&j$`AT#F9jBJHa#58d-E46nTaZf{VP8rX5cf}ZysccU5(lBFJ~E?0e| zFGic8SAA(47li|lDyqubUrKhj=SU9vXZA;Eag&JX&+6OqHy#$%t)A2D&XvHqXjQV6 z0ZwjO>$z4>&Zd(gHpRX7FzzwhAAR+)P$nSc6rxt z^MDf2#9f>5MgQaC80-jH@qgFC$0pvAVlyJf_y`s>gxqaXZhCQhxfJtgXRlWL+|#4U zV^%zr5_<;EQDAS>x7H1X6>-HD=kwIAe;a78Xi2ZbSs*uZr-pS$&`$Nmq>-fZk?bEM z+-(38x`6LL9M*Tt7~Q~Ojxi2~HH}-zK7{sufp;LKcrCYSYWoy7vtK7Z=av@Bm0NG8 zyECBaM=m0RsSdW+@J=znH_(k-Z zE`ok%!0q$sy;$4FpOYa}n^RY|GWb-LWQ#?r$sD;*!1bgDW$*0N_nk|AY@%xSR(eo- z{I8Kcr(vY*AWgOMAGW{vEzheZ+ADTo&WQDGkBNpZ`gOERd{?cj*5S+d=UhCAw9Hbz-XdE6#j|Ftn)} zztKai11_^ygB?VESc@N`vfP*p0QL>1F#DE%%1zZ$B@%DORlNq+X9t^{fNy) zXl!usYI=;PCe||UP(AWLv%CaDZ8(Sc!x0WlaBk+`ri!SCP}^|6AiCkUE0~UW&E)@H z#$qzbbcwAGK2cCAQcMOsO}wG&Cd|U&O|9bg(h9sXuL7-&cyhbBzc7Dy758J#6um&7 zBGSRX^Dn6pE!MfOSs)ad10?Ry_u-fm)ZCemB8qhfWhUlRrAzCBVFY;#zaNlCf7s0o zZ3NB=q`0BGrG_pW*|F(8DF%Ek+QmL@3pbOnW$x($Rb8YL*5mTo>R=bRjoSFYAx}j{ z*O$;H93XY;i!|LG$cRb>J_%zU9=9bsVW{+oRfZIHDUKExQWn*q+Vh=BTe$zflXT4i__j?oT017z%q)uLwg`^CNQAS0lu()K< z)vra%&wzQVt^J|`+vO96*`=Pqsf(bs3zPnleX8d1T55eG#itDRrY@&?Og8U4r|NsZ z{G01RQULpAhe9ua|LQB+*4rKs{Kz)@UJhUQ0$ci~@1QuhiEA{- zM8Dbn%LC?tA?rhOuUy|1)(oHsI<476I;RI0oR@8>#{H&p;IM=x%l_@MT|Hor0&!!+ z(P2I*7pLiiREJ-Y)a}KX=P5u1VvY{!Q0@8>?}2wbWZAb(Qqh=kGQwz=BL&F$Jol}U z4=5>0tm|Ll+;rg_(EEchLswZ2n9gXGY8tQ=XXS1bXjmRqOPr}4KxaS38u(ZIAJlzk zSX0aTZ!8;hOWBA5QWX_Mnn>>`O*+y$3eq9e(2H&qkO-)umjvlZuc5P*CQ?F2Ab^A( znh+p#?u4`VIp=?$d%xeSAAC%*)|#31&dfXWEAyqJjtq?Z6Uk=cW3WB@>M6$;qSJ}e z*ZSena#w!_=48K}JSI2?zsF47#^|XN3tzlH6p11@K2m5>M+|F81^6altl|$o=!GjlgJ%)%Tpg3TOfbs+|b57YHyUuuEM zIUEhte9HW`hM!Z+PFt@ivRx;Cv;r@y>#Qa+QbrYR@f^Q<&f|%wTbTs2WA=x^IsgF7 z&bKtLw>#-T$so?A${LMc)`I+7eloQdLdHj}Oo7a)WZAH#*9f619gMqc7?5>bRHC2tL>>63fJwtpkcm%o zZxkqu)*u5y zcH!spsq=63V;Tp3e+&SxdE;cd3IVd`iXzoOjrtYqaticqrk*DvREmzd>sF2Eo1QzE$WbVxI(*J_7sQasZu#$Z^jN`dX^FCDx6H`sA}U z4kzfs0GE1{11u57ts0HqjjN2b13AeMAlaIsNU+`8Knv$Lncg4cgm{KEOyJibKk=md z1V|}WA2=2YL`1-@ud$;kZ$spMBYo~PXDkIUs;s8nn^EwfI<_hRuw5s80iUa|awK}< z?PI(_W&`#3$X`kR_gD2&?GxYsG@rm#P7&~@i#c8w{)X37k!>ybt`GT>F7Zm6-baGE zb>|?TZ-b(ma9Cb@9-BW|6z8uvzZz=(@6S0=0EK3+YiqSIxeLRIPyM;v5m+n@`TMGS zA@9&n9N!m8jVaA8DJrxIp&Tgy{6@kJz5OH5$4MOyc>?2iqi}19TAl@<3G~jeJRM|P z5RKMurE&lO32#3Zx(w02Lc$ZXBYn$hOK_dlPa20MGAn!sfWT{*L{%@ki*!x_aA!nB z;sUi_4(a)vq*C)>a5A==bXwk(9WH8(zEPSA>gr1%5U!AbK1aWJ+15Mk63?gCO+}+M zfxI=Pj}oHIBr9|d(&r6gyzQo~39enb?Pkutjy#~{g@e~~bF0m95z1@>V8?G@ZAb#4 zuafLN{vZGM<&)6uWdHG3N@*4R`6VonmpP9uE(m2GhpZ2=^PGMGy8o)3W30FPJ-2Y9jl z15&%1?@#s=-NBOA>nb6o{D%mP`BG z_7BX0&wyv4x1_J)hN3p{U2lguYOn9Ja}@AfI={OB`PWwo#3(nqeFbYb$*o)?VBH}R zOb)S!kgCh>z`TJVDbq(9P=jaCvz#soPak#V()t`-~m>ItacUTyv3hg#d0A@&jN;RpwYW}M5HjpCNekU)=)zPCGn)$G6!iW=sl zEt5<_yiGddN-SR02Wed~)YDF1qo~g@X7mGUaaMxW^8m<8OjP8#^14ooZMC(pQJp04 z`K#T3z-MjGC`y0_N6q@&8zzVB*0|mq*3dMaW}bhU?lck0R2lu^HAc_%>IU`e;s@Sp z#{=zlYEjgE6j2l;;&ymKzLPqsq(Y({ROwHF66_^MQpfQW>;pWp)f{V@PG`akQ^VXdk;#|b0X<+V zXsxH9@Pe{ULbs2>^=zuC!<6+mj((%m8DJW>XPCLu#{jR1ISj3M@~w4zp0mirOAG}*t?ar9 zOA|ofv5e;n_&5IC)a^NF17TDayF4@{wJx%d1GB39{iZCFGSP~;8Amj@(Py=C2;uFU zUb<+)Q{?l_d@e;`P2w}N_;YCYLF&exDuf=NB^|YVm|ZYKdDFZuD4ZOay0l#feX&3q zBNdAsidtl7({-?zc(^`mynm@u<-hS~iO)Roz~X1#DV-9YmV*AhpI~fKJhgUH+PGj1 zF*^?b^7(h48*nT6Pin`N&$lyayAo54E>zzOI)8w~JPoyQ)Ja9O5Q=Ja{rAed7yU23 zTmS=aRrL)Zm$^$7&^Hy8keDFS+KIbm(TeC}op&s|LXFoE4eLL3c4-!hF_tMRy*naL zT#l~!DGn6s0(!8@*&jRB4KT9~06n+hB8J{R_hLVURzwfIO<-@jkrj@}i1*89G?>35 zyp+A=xB1{jB8MG(dxYAO13a7qOfSMB(?F#mz_%_<-5+DQseM1m|6Q>FW2N;?3k&y$ z^)K2~@a^{2ci$>HR5hRALk=CTQ4c$RM})N@(#$2}F_G)~V*6!l?FBFSf!e4cP4{17 zBQ~Y1M^epb_cO5(ZAo@TH7)=0;^lLi`>8%NPKQZm2^RRP;3X)^$`0R#2z?Odd^K*; zD!;6iiQ`*$OY`NOjIrB%=EQ6tKBbi4QTqk|AozM(w-75X=7_JE|3t-|9syX;OwBsN z0anzJRBp-)+T-%*l-03D8j37Sfyf9OsfCa^A`mPYRz3r4P-H^(5U=^yI?Lj<+D4S= zVr-n8C|J^r|H>O)^lU=QYpFPfPU1udL3uv9UCqnqVO6vKyf}cwcKBIH=fy-A zL0gf3_0)a$7F(`muo1Vh2gPMYm5)KsA0;?a6`#*7=gqJ5QDYgo& ztL_-B_@dE1>JP?!>vr{DZf>rMtwqFQ0;&*2`V|&ZwK}Vhe;Zt`T{2-Mgky4}7mZIUP4cY*cYd#S4L|F>2l*SV#w-)= zKtGo(8y}h~#a%@EaJ)jtQBZTw@ztxC>5>!)&ZDbf{A{*x-0I|=t)u6Z-H-eaemmg*YMtkQAiezu1-T4dvpm-49>b^{%}_po^>#|}Mk8!{9-S@()DIl=Z@L#y~k zG;oI?wxw-;dlHq|eh_1M@jbi--fw&x7R{;-)k{bXIUO5*CX7S4*vcFoyHmiais%X4 zRgZHS>iDQLpIbz@XM=y^JJaH=oNMv<3YH%SLCa?aGcl zyQ>6WXlFygP(F^nhsgBMvQEOCge@CL0Bl*}?#R;?QGMNg9$rK9^#>Y!_1>nFm`r`) z5s%T1;|O7KQOivYb)=Rq@tv+CeM<9ac4nPW@tDQeSuYf3!mU@NI6wi|jjgm`%@}VJSMg^%)2dNr^iI(D(p#Xo~9xp~9Su+q}5om|ulb z5UIn`DxrJPi9v_xjyRae#>T@5Yt_XUFeyoahK29+!cs9)?30u3y|13OhVRTbNz)T@ zha^We34Zb4Lsl&UpJNZq^$rvAP7C~|M_*dt)j>i+ZOJ!bJ*gf8(KZ}Oz36DyG>asp z)`epWgz?J6 zkOAk9vEoZNUBcz3**Y(bBydN!mR}1^_5YL{a$vzXBakEfc_q2y4yqED>SD!T70lo< zw>I^P+EQ~_*)<<@#=D?13KDP@Ft@U+F;I8W`iN`}JN^!ZD8j@vZPV2Jr?gPAcj1(g zT`N67OnZSwi?04@WKWLSza_34I|=eqc1#4YQZ|dJrmTIOpQiuGW@1QnA)0;5`rWM|%nPV43u&(I^*#*x=^q=`Sl?MdL4y zS65SY#UvjE95fvebq2L$3s4b;e$)n4i!nSS1?W^S}(rfb^J!L{u7)I}d9UZCfR*517; zspgZ9odW)1+|}Wfp{O;OoZ}^4f>Z&UL`Pd=tgfX8MOCmHZ|V!S4#OXeih6mTRU6Vr z!Ef4+xSBDi-`KWR;+&{sZqzLja9J!l-b%)e{4(1qU%q<8Jp1J16<#VfX!G4hliFz7 z0>3ogd7G^XbW}%G&{4nR5QmLwlTIde;c7AKf}3+LRmw71sR=!xxVd}apDdM-Ua*#1vXBO_gk-Z_9XA5X_zqC7o8)OVPlm@iLl#TcOX>+UM?y1vC6 zha)VGEe%*-HcPy=OTg$>TaWwl`_ph)vBHg7*-OfW4ugKA&WH0SN<_IUD0o@96{WQ~ zc{$7S`%D%3joUqRa6N1g{~6_FAeyxJLY}!%FU>zc;v1m2m~_}Bas(Lu#(Mlq5%gZI zubmYS9H@IYrrVpP_k=@OcZ`n$qKfYF;k8C1CWH<%dhM#<&L-_V3x25&_<= zCI}C!6Nnt$mZU5`S=Suz5Wz%7q?>*TC@ENr|G^pgBem7fsIU)6)94l53L1y%9m;Yr z_RaLEduK(J2ip=aL+861N4)?U&%bs79|b_@SGmeiq}w)Yov5?Z3Vg#Am{prI zu4()h1LL$>+|>LGwfxknfp=Vw+x8`h;WHDWu@_%c$%D$aW_|;?BUJ0@vkk+>>B(c7 zkSe0niFsMmyk%8zj|%T*+NoPB`vs@))C3{NpRy{GjhXe2yatbly^W>)*d_v#atbyE zw4|#flr?9tznf4cOB{MT`K`yJ+h1FJ=4;d&tISJc4nFO?FCCbqkM`V&0*?pLF9k>T zko|O?%^~u-oFo+7jo7VIG&?@EWcg(rc)xvhFrNQw74+>}a$eLo%}AHiiVM9qd<*Q? zAMIP4wEAK;CgGzi6i2#fhVvM$AFEc4CX)|X)8tIc9>-hy2h~o|l)MVt)-m1KEDgWK z$!kJNA~*-@UQJ-Ay-fl=N-ov+cIjG~esJYATM9*L&DuG%Rc=hR5cGpb`^CYEqk(~p zT6gqvrSuy@1oi36N*8azluDARc9(_Y!~yM&Mw(szRWF0(Mfn(rn*mrlfFW8%`r;FC-=cFWGO%Pj-+d2(*px8)w5&!7r zl`i+p#-V7Rn$wo|Fjpavabl@RW6&f{X5%9vlJ2Vt)k9#zlDg_B%;6WWMF>BNseyMS z28z!yn;-SOi@dr`n=7?2nDLuSq~}3X1Gpz~m(WXy?cIjpN7UBJM_b+xahVY;aBzrJ~iIM`uxS3>aqX8BdG0M!S_+q~nm*8=) zyvElw%5k^5#MLFre@Dl%DQ2hT{g(vMh_N>49}|5bn<3@%oA=!OKR7=(W^_pz>bZra zW-N=+SS~j4UjO2a&vp0LC~;^A5jH@!4Gss-R*YyUDa@@Z?7b(qVbaJO;DFh}yBe8ANJd$V^7WGQZ@;JvI-MAkQTNikYZzaqX-W){Pr zRN2vJidwk1nKicMhIY=99b+~bGXY4Wv?;kZ88k@kEalhu=y-84dmkhW+AT z`}66+?VH-z5GssRy*)Im=dy%Abg)!##r)bmrSIYRpM{dNxrf!M{?92kF+H|W{yz2=GqshQ*; z`=88hv+WxryuoPWCXg>;89~&@hc3|zTCn0qZ!~-QEe!NUBABz;nyt1R4hEy_>8J@9DbYnJ`w9$+)wTy(<>5;86BE8qF3~7=q4cJ@<1LU`Rs)d0rTzZ~Mlfc3rrh zXy<0;u{%&>n!*~789GY#c#{heZSBt`wQ{|%T)Gz_``H}o#a%Fr)Vu(SuIx?K?|d6Y zQ5br~*aC)xWb|FMCTuNxx6G5ac!UATl3i0=EWcuQIGkd7w4@1J_k1PD8FMN))ojg4Y3j#n z-s9N3vwS1hGC_V{o!p~-(fPK2K7iUEyf8}bEQ(y_BLyuf1pbOOSYt&{+RFlhNa}P&NMA(n=# z{$cnr^+2*`b#&uUlZ+Ipqvv-ZhyVQ~1Ae4hh`-eHwN4&Z)tEHNO-D`}`}IGhCqkqv zqZl(i!yMr?(*eG<7Tmn`L*5Sy@K^XEGB6J?YYynFBGgZ2D6 zT~1i_QfiSoKkVDa{><}l{{4~uLw|@=gXxGL1f+FnROjemjijSNH~YFMYgJ6ql}l?+ z85MFeWe=EcEwUrG>MvL!ca(&+=&ywHHO06z@znJ{a-9CNF=g0f`s5`4^w#gww;8o& zm%{2)pj8PHBsl&%D%V)!{O-aom}c*SB-5pmMvD)?$t;x_rw>_Yi-p)%S}WFUKWTiw zu&awyYoJtOBg9U#JkWor)0~%>WZ_s;ImC;PT%gC=_$;#4t-a@;eaVO&GLAduCx&Ra z=kRP1Mv5+TPGq$=4t+t@5cf(f@zahKyH=s3bqQ(5Ms(aL;GtEyj~rN`A7Ss^#z1e9NS{H(Ehod z?N0udqbbF`u{^B3M@?NbS!-@k^R$3`5@LT(S{FH-7gm}NRt7F$WiZavx}ucxzU|IQ zM0jGLL}$PaL=9ZFnzf9GLtmck6R|UaJw$cz0Mo>})4yaX;lDxY-9z%1Bl2~JuJaPQ zpmdw8^j;=LlH${sf|XII-y9fPfIROG3Yr=;%OCw*6q!j&6JtkhIkI^4b*_&tHCuQs zJNm$!j;(iw)Wy9)5y+O>N(Ks%q7^_a>rNk&O@4ej?Hd`scSCk|x#g(pgNs{wRLf4G z5c6u9-X@U&U@L7KLAwQ-liTHt7E0>;5=)jPbUrg&F#yVE7qXwp*J~>DnzbR;#)cK} z0v0Y0JFBYA36Lxo{4H6=u<-p0=eNK!Ogx?Y*X*9)cGdnh5caJ^m**;~tIckn`lwq~ zXClklnyq<~Uwca!uDv+3fvw8|Hn15ww*Lk5FQtbx#;nbgm#;{BnW7&nxgSkqvPReT zIAH@__akaTOb-PyxTb4LQn}Q$P+d{!5@f2h#WS$&7HzG})H_hOqtkK3H&}E%Fb8a( zn8t4{H0`XVTIuxv`DJ!j1NtYv8@K!yOZ}mM#N8PCSGnv{LBl#7W>E&GvImaQ1}s=~ zmB)S9EOCGR`hXbNzKaF|+KD{mGLY3|bKXKEnt6X~{@hhN5TuQ7-5_$M@0)XDa(e2U z+VIQ~OG^A?{aoZUiYbk;bt62sWk%-h2b)d99S>Rg%Hp0bTlgiN4w<5tc#8D-Vewj~ z8knE9JD`6w`CsPL0-R;;lr|~b0Oz-ZzyzwzW%{Zn(pT8zxY@0|y<^F+47+-RtR|nS zWuWg=uq)Br`kUp!WUz%bth{n66({35eEPg~gBLB}g2gms(MAF$Cym(EE3))WrNA&fL+n0=|*QUHOC5hLhz9)klk)=I z)_ZkhK9coMdiX;C!5ugX7QK?(4~FlF7_w$!aSOT2ZZLI? z*)d^+*UJa{<^r!M?;FIinA#HrW@_}8nqsc5%H0_uCE(f__vhEZB#r{q58O`Q77neI zMpWzfd8F0kD@!oo9^~a`r7W_J0Rq&xMF(^L{8{Ou9HmjIQl}?iedR>Lhfd|i#Gk1C z{Pd;{sRsd`N`r+zL~PyG8A`@~aE7Q7mdq>29Cv8-iG{sIE!-bV=%|Z`dgwBx3Cy6P zuB_#<9fkE+s(FDEX{Ix|?X#kpCd8wm=Qny>qs9o4<4Rr5W(q)lzz{lN+|Vt*b$7Sp zjd=2Ghl^iTlE<5E_V1tvrR1&*HF!J>!gggarD@SCuCzIQx1#Bymb6j7{{4cS6L}3V z(T*$(-^^01@yo7LdHN8d?FvJUOv?IJBu)0uO97O$&jR6V5hM)!xL0&KvY?Q3agqVv z%ak+r!JwR{+iX~yp=Zhr1Ogj`a>^SM@mRK*BMIu z5C4D~s*IyCyffUFhN3HgA{k*q`lVF%?K*6gJ;<)a>XW}n=1>Qzz{y?X2+)(B$_x+{; z*a?hl;T#aiIA4fr1w*U4THj5;&v9rP`U4_Y0m=qpw=DEtCtKu!{B`~RrjsYV8Sv-- zDHH5J9Nt^#YDxB$R_xy0sk#8^b0#r5=5;t5ffJm3w|oVK)gL7eg|{FtInG!C|53j8 z-HR!UhU3 z<$JmV>6J4zDgZ-Mj#}wDhlaqqai=B}5|D5Dcu2SWkMf;NbcSo{{>yMcbOBZSS15-8 zTqnX=_y!##za^>%lb;JZ#=@E2|6`qiMUZ&e_#O0Z%hne=^YAG5zrR}BYNF|7N7++A zRZgyTMMM~p1J*#*8EfE9)NIiA0BpG?;?$(n%NF8)Fh|}xWTt<)D118bu0sbKeP`m zfcUfB86^^dlAU;EMYWvA`3)_NL+aMHi|I-k>4C+NbHeWRfY?~28&0#4t`T!2va?SaDt zW(^y7iIXs~b1${l86?VBuN9=cGcp{8N&jpVAH;FPtcT?73Z`q17&aR@unaWm=NMTu zf!{P2T{Ssm51Yrp41OOm1P{)4so~ns_)%fHtuEbN9H>MkbMyk@SO^Yd!DqQ2QP~_o z{$eFkX4iG*??yy;$n{mZfA29Sf0$v1e+D=RZ;BrT0}jFhiG!dW@_*nU^fBi%r3|Zm zUV*C1@MhesLJZBk>yG@ZA>>W?trf^n%e|LM_IhGT5)SX%mwk?|s-K61eO8``E+Ffy zb4J@%&#s2!)r(e04nMyHMXR}DHyY0SXL zC6Si55s%yrcNjKkzTEV?6sQZ-@3U+`{T>SV2j56Q$@=qaa`Hm1J>aU@Tc=5~Z@&EY z*IPP)m=N=$Wmjv~k*LMpERqJ^DaOe4LwR>@n_gFRlrA*-?c|WE41c6r7=0kaLmt*9 z^-6I$U7_2lX01}T0&m0jl1{tXq%T|$t1=CWL;;28`t0^^>X+E_Q%zh=AT{Z7k0MBOu-%&P3zS> zGW&Pr^f?lwZmUsSf|*zdXzkK}18mQHF}yjyl0alL-^mfi`r69A_C|SPYnpoa!hOn@ z1jPxa+b}r(+m@BMBd6=Ib7oig_c*$bOO`*MN7Sjj3B%jzuKD(Ks*RP6TUZf zuj!o)Q!i7h-yIfx?s$H5ql69DQBEQ>G(gu-zplk3BNn(&?Rbt+$vM8Qo;+_B{peI7 zQJbIi(5Thvhwdw- zW!J!)y*GiKdgGD;uu+Zb?5{udmi1TMSzxF0i*vd|0jK^oB0){U{nA=U6a<&WvemX{ zusaE5_o`{@hP0TJWF^Ypb-um+3_f6&&Y$kuGiI_83`huZExr;f8%MTDn4Qaz9+30Y z7{jCN%W3)Dm$o#4nM#(Bhf!;z??+p%(a5ytatZC(FZr#2=l-#CUgCkk50jR%Gsk^> z{hh+_^+6W*FNDtp44);&-FZ4pokW^g_Cvq^!$l~F)>|(oU!KWIx3T#AMqhj^o=~-L ztS7_I8b&cV=lo&nzz4ZR3t{wG`<`+*g0^GU+{#s*`u5}Ez4Ykv8g3hbMlJcaTpZuY z4&s+b#fe9a>H{Nl(yAuXy>WUeh{@1QJ#EkP_`|nTvHe5o60%J~gi(oYQrn>Sj|7QL zv%=i?>pPCeJK^|);kORQGn4L^Sc%PmVHF+%N@k47g%Dgq^u8mR{d>jXaf~%%DZZ303Eg_3}miB@8bm2bY}32yXA7v7C@0gfQnh z=ui+>GBZ+d@WbJdrB+WyD5ZEv$4!Hj z$wk0Xa6N5h+hhQQzYewEipr>NdA~lFE$vm`iJZ(fx_KP=RDoyK9d>6Uau=l2;}uRC zlk8y;OTqik0xI=mhQ;Rv_S)mc%qLi?e!g>2kd4!V6SmYFH5lm%M$}2K7I6M*RARF4 z*c#QHN^82_My9r^Ul^pY!%}eqR+}qKpa3h2N+A0(3tL6}mooko3zYE}mQJcJ{58aH zGFuVXpOa1OtpA(Rpl^rJS*&q=@?d-^tQr4N7I`C=C8kZuu2;iJTNbt+ek+s(r4@8u z&Kk^_(7s9`x@D9Nqqm)Kq#uD{f!5{FRp=2*+)Asaw8ON_laxW`#q5}G_|SNyHM1*X zTSO#YC2gA#lU=htKKyo?YLZ~n@4l@&-APOHfy7UAI5Com_cM^#%9LKo5@~ropD?)= zP7q7m3d}#Mc#S|8iysfoAu#RksG*&fgylEr?AkXn=hDN#JT01cbm`QrqP#A9BX*4c zHXRsnt=c*x7WZyw3D8cAsQJvkPkVSXDCJ>IW46M+8&Q{^ozhVE{>IiC3f-8uqHmos z#QQj`WOq$pvUbcdRR8+;;5nL>^^Kv4NctuTCLb7kZYu8>C+ZS(x&cSOat$z$6FN49s*L=ef_7MzW)VLpdUZN+-Q z1nUP+T-iR(ckt2-?9FO#0Sev9K`#G@br-$j4yF(PI-hnH9dj71TDYz>TBAj*9UHK8 z(Sohp1ks}!T%lSO2l>ma`58Q#K(iSZT`6OBW ziESbWCrdW0M!cUBB7|_e`mOdFvf+5iE3 z$yC9bV1|>aW(#FcO{wBb?Zz!4Jwq#eBc8r|`UoqK}ntW1EeWFGu5Vb@ig7Vx=pGrFB@eo%Knq|Khll z3}#?KJm5@Y|7J91e+^Zov6|bv{ouv%ulaK6ksd%Ug}vxed6`l^^*-C@lZHq~HfmTT zd`(Bjq2luSO_zmtq_uosmA@&3DWTIW7U}#UYH#Gj-a=}MbU=V; zqx$R@*LZ$B*H>#6-1hch?f3X9T%n7ttT0z^*DNQ~KLm)wi!V(;UX6`y3$Net zT%o%iQE0O{H}`Xz*grLyFgU&PLfY`!A7%CBHj?bV2VQ^G+#u_oor!dT^~qF|#x92+ zyiqB05b!M_`;WPyy5@cQ#npZ3_DUr!+XaD6<0VlrgO$ zwlL-!JFI)Z=3|4m;}5`ACrJ9Sv18FvIFHN>k)Hb|tOAzKGze4I_*@g$i79dW(!Jqy zA(?#VvCr}Q4N#D(o2y&j=t^v}4i0JSaXVF%{5$7!UuCuqD^ou``X{OHc%$a zCi+!D%#2l^)WAV#;A|-_51e4m)*Tnylm+MT@DDml2q zEak;Nytu7f0+JnIU*laeg{I=#T_>ZqG+#e{$0f1tsicthlMFLXM$`oy3FE^ZOt@^I z__~B!7Z^QxNu%dCVLZp}kqHE!sjj5Bti+2{G2Q}C~u}Y=;R6n$QjlJX+2Zsf)S?#;J|7J*BK9gJ5+!~8M-06z? zQzQiELORn!(;LZHHkI4bV{w6M=U3vVfF{k^@cgLfBa0n@k_JWqQ)Lc8@>HLk8tv}5 z5X4PSga2Vg&_W!ah+TG*A0aLz^w1tuu`Zf@zwR>D5|wgWLTbV7SXzdf^naHXU)U7*eC%!BB$&$iy`*+6 z82@d&la{p!q!*5h;T&R^h((Lr5aIF&>s?Cm9L^LY-Li8ov67c^D}fP;oLj(Mv_wu{ z3vQC7skTk1orb3W?IU#-LR?Q|Zcxrgs5H04J%!~$@Yc$2MF)Ql-UyD5FSyLsA~aTi z|JPDDKZx0br{b3Z17W;mE_cdyWB>ZdQ#P#j^Qe?%35Pt~fOV zoT@_Wq={7IJYYPR_lg*RmBp3p2KO|>Lz)lpCAb*)N!G%F;K|8rLv&`8N$v@EZCV2W zM$`v~eU@{PCTW=*ZqPO!@*+N>cXV3)q)YZE)aP7>r-I@~Cl&hsdk+hsi+HAG(BO~6 z{OB5ehcC%d9+|n69!|@q8~We>2=APtHd$!f+m$t4OLAWsxLo3*#x#trMW4&x2X!%} zctspbpAoEJ$1%5CuV6m)Xy5AMZ>%#bK`zooF=hj70LlELt-3OX_29Bab@w3mLZp8@k-%W1l*zuI6-88AUq*u zEfVQ^|< z%Kb|Z8)5BoD!dEHSrE5e$k)-ct2;sE%TT@^l>pDttaF8D%_gTkk3s^t~$AU zCGfyvEl3R|n2l1Hr7a((nq6~HED@f0Q6i+a`$w9uw~2wB-xt~pXN!sAn_XHZ+$25y z(7Lb3O5#S<SLCGrua{ zcsEg*jN8k@WiE~sejj_7GR!Xw4;U!*b##mVbXaNh!h0@pV~LCy(sK^xRB$;n!S{RY z{vJNpvCtO~6DZsN#U9{Qvh{Eee|t#4Jq1vZ!i zkXci|ak^Oqo1mjh_|O+%;MSs({Ru^~Ovku~QeA>U=l@zGO{$4cm#I#VeAWjuR&xfw z_XJp4H;jI(XKMxzn8FRdnsbP@5MJHVL5poJ?C*~xrmQVJ8_y;^f+Yw^QEhTOmZIIh4(g1J0ufylUx!N`O&PB+vB4{I2XT8vOeF$u zmpMB}Z?^Ztu8urzQfCU?5u{voZ1`wuvf&o6{(QA?uTeR>ie-GejNg>mJ!dsYYT$u{ zd+$L@ufPT_OUuG`BKo_qM_VV6m`qpT8*upi+d-J^XV58lb6^*+KNDXBogR9%*P0=s zf&|7J3xC`T?kHhMuuVKx7KlvP6SPo3z;tAeF|h9=es|G3N>t=TlT z14j7*8w+r5Nhio3D8aTjbf8oZS{iXk+r^RNZm8;Kfv+4r$BV$=VrsfJc8^x(Z|(an zOt_{URVADG_V4`If(hFaTWp!oAsj5s_p?p}?9BX4Qu4V9@9^`9y)!pl zrq9iezIAE2J;VQ>J`w4RTU{ z(q>Mf#~W*K?y*?0gJa)oX{9 z`(BF^(=t1$+W(!1%+rcwh1DKXuU7%Rz5>A40*{kgF`+te zU}e16eoXx4h!E1KwO!iYx#VvdNK^${dP5-$KfU5ARvt~cWy7rfCS{6#!F>HRIf7(S z%CnVQ(FB`$aX3_slK3S^3_k4V-*K%n4k-IVO6f?i#0W^=yPE^yOt}Gi+I+JP+}~GQ zJss%X>?1swJ^ibuN1l}{an}~Le7yp_4pjBK%vseg8kW%tby$JSlsHO6r)kTOZL-3mm@?CMrs` znIG{KDY0!Dyb&Kt6vFr!reO=8BoEIg0Cjz_eUjy_xdxo?lS>tX5cR`n+fOWIYWFs< zdjm*)h^5q|3OH{^Q$Y$T?a#$4pI$iAfkTGZ zaWW^c&5aX9YzL+W-WgsS(z53g4owzs=uwsbGSxX8oU*x)p~SXDoL>D3I_HjV)T0&6 zoZJB#lACx17o{PSk<@~*f>bPWi$bQLNcDK{dSisIluu>qkVf@W^TYfW7v&G|Wc^nn zrJy?jGOZl9(*5RHzmC)q#cr^58gfvdxRIB$+OdM)lolEobL7+wGW0OrunyRNwdzkj z8Gl`O(HNVM5fR*wQ$*k*0r6n~h~Ga0;uWQGH@yQt)Gdo!7+%*|Ectz9L(BtP=|#(} zSuEo@QP4-4M@0jUN&8lo=r9IEB;6I(i8?y_FdmM8BGFo~2`t$Cx^eT$GX7KjYf1&=(3r zMsyGe&t(;bM|uJ=K#mr5uU;VHRX+BR#0=n1E!-41&`@`H>NnXa-c-Q-%Cv0gGWFV9H93r zw#ue7K%2m9Ohn}hysZAfY}x@M-vdbwCt?QM>>dk=BQa-Cm|NjJcsUmaFwpy>mLrbe zPMfS+wpE!p)m2%PuFQ8G37kZ9BtnZ86552;35Vv&w@?c{K=DHzb7^7onk*sriXvhj z_DF-;rEA}KG#LM5+SVkniG!4U4bOe=oHp&s%}>23_BA6fV|Cpq?xSmoQo*UAxbdvD zUU8$}cP-|hIl(V>lAY1XdWmh5Ro*b(V4T*4r6FU*%C2M6kSe~(t$~gLy;(;cpNZbC z@f}^xz^_yHA32$dj%9&v)!t~Q+tOLIqsPu3?{3)1TMjm=d*}y-Pp@z~1;tuK@>)YZ z(praNEV_%u3pI|H+Vq5s2?QJ_L+WHsoAthAjHJN3Z1aM1P}AGFuv|^X_O9@d$>SP% zfU-NNI`L0Fd*vpB;T$ch>0GS6-j5G%mbzDjeXb+gvo>8G$ew($1}5tmY&v{es^Kgu zfr7G3z(-@-*yGu}{S)thB!4+V1qCwyLX!vYIC&pmp-?4$`SS%Nz1@*jQ|a_4*I<2S zmmgSIrZ;kIHXJzKOr6`!))Y@2Vui@1jRC{*nxKlEUM;2oh87n_I?EncYippS_dd4& zE5HnCwDW_zsOAEsQX84=Ai!k(#|Z!INKuQ5DL~_e|Ic81xe(8YQQ9I2SsqGp05IB> zIph34owKBC9Pk`K$xH(Fir#C@2CX$d$2(F(_3_HCJM(&zcOcp!BtVdN1m2dHHs>7$ z&PvZuxd=&?Bf-fEGW^wF0SF(Z+M+X=RizJZM1ld=HW|k71!e6&IT{UrQEe3Nshh)19}jZrasUTXIP)N-#c{NUR`zD zOuJOcNeEO`6w=2`x<((spaz!F>T3($SpWdXByoXyAxQ9Gd?&r4ueGD7DEm&N>QC}| zU=W~j#wYkk?yq2EUpn-5(f7(Y8=)3hPA3CQ1T^OfgDXw%O=G{03rxxY8_n6*1M~&b zt~_LX`PS5~AZzZY_VmtydsDqL4$vx41a~m9%W;E~&gnN_Xa)4?IWWwU4giBtp5eHk zBRC~D?<2F4bX=>TcphXWfL9erC9i5l2$|yBoJfFvIB@EQ$kCEudpf|hjWKR$L$Cn6 z77)jjIN3QkK-qiF?#7GR3Qtr};9Q;1sCWmCA(NUTeMbrWn;;OE1leq33agyE_OZDP ztwNTLmmuk2+<`zo@Eb__gjUc&en$TP;4cqQ|NB5N0x9O91d4qJ@(7^&|9CL|DCXh; z9an8DzY0x(0_Om1g<{P!=a&VFIo@G0hR{r?4aoB$n-fNDv8 zroi@-^yxlVIi>(WI)}IwF&+Gu4}ij)F}8!9{os~u-|bhy^3CUpR>eUB{#6BCvdo+f zWA&z>i>K+Q6#`H!Ct>Y z>m78(-9Qne#A5H@wOqTRPs-?iZkrTR1UUWqnP(#WXww7D@r9BQrt z=yUVY57SF|#m*(kQTlsxyuYj`*>^5kj`Y`GJL5ObZ(=mkD_5uK6XB&O=TBZtBIRA~(;{pTBLmR{bgjc{RjWhBA&F^{mK=fK`vX%n-JQ>u(pvM;~G z*!%{0DTrC_IviEtxj8-Mj!bg3?(y%IbfDm5{haeu5V;bT7*BabKiS&254J7E^7ut%tI{%6a@6hjpj=m>aVuCwwq`qAdtaWCYRD#-%7{K zxzG8NQ%RH$O)s=EANAHbt$Y8hFlU$^<`sK#=jvN5DLg)g&bdj8lRX8MrE(Cv75uJ3Ub3RFgzha|;ryTkQ?9bO zb1l5%8hYJ4+UuEZZ&iOuhk=+_R4gb123i_UXgH z_yS-nLuC_x!|w8abP9r3v$fNU%UaE_s9@a$czjnJ&ZPyjo-ch8(p4MUa{hm`k&HMq zzh<)ELMiiF4(|D6b^xV{XT{uO;QPTl@HC}+qV#k?HGoBUN2G95P~+hCs0wFKXJ#+I zYYSby?{i!0$6g(imy^3HL(ys_moZfW+N2hPz6UJ^qL$*8cq*SJBfsc+S?@gJxI#^N zv~B`%r$s3iP<65 zQcPcPNUz^rtH(OT{Sz{vC8EpjhELq)MTpQ=x5bicki92* zuV(bItN*BNa^^jLjf04MZS&66|JB@g2Q}Gr@x}&~8U(zBTrhBiy6Kk3_-Sy|Jce++OG5pyJ8uExX;(+{kyqvl! zOBZvQk%d1pLr`GA0wrm7;*5nE11m^WvRHBLqs8+FOvzVd;xWeLH%5*NN`L4B5m zEu{EvdkbM6#&Qdyldh7=QgPM`Hl?Bma`d;==A_HQ(WxC)G2U-R$xDGEAYjG4q-TVA zRVjTp;7GG!UagB}_pMb6&1N<)kt+8$mF|cP6oeg-)|TXMpMCM)67^D@(LOw$uMVs1 z;w((CjmJMf&4E913M6_QgFP1`A+(lrXKU#sM@d&cI!*B#<#RMq`*)Y5jZ0%`Us?yH zA~O^?A@uZCN%yhnlLcN%(3~X+AupB|Wnfw|0q_>X&O_fS_IB#2&(stIR~KNX?7g>C zMCJkgIw2^;kkeFIw$*#3K&t!Zj}^URrcTH!93}6qe6Q9xGmy+C#V&kND~JUD@VXH# zJ)`V1W)d!OZmRisUQu?@RrVa8U3_Hcb&Y?`R#r`q3bWLXI(fgDm9UdRzyx*DpqThp zvdx=W@lJB14;QQzKvBw<7OWXOUw(C~yaeqDdbxs+WMC&xgz~1*c@aIpe!GQP=}DvK zFO(sx-(SYFo>%@0SFSYZQ;wUw;>sC|7cc3iyHhJeWY1ub1!Y#LT&Zl)%e0LwSh(F; z+Uk-SKW8vfEb=^60TR#Q_9(DZG9GS(U~YQnwfHC~OUIw?c7f@felsl2{--a4R6PHU z`|nd?9_}HIbYfvH**|LcEVCxGMko8>m66GQh!1117|L-&hZh~*Y$pl@?K zgNs=$=n?i1@(zFEh1zh}U^wGZ4oJAs%1|P-*{xJqcI$%8-ZYZR?NQrStF>2Gv<3r*Nq&H^-Ql`XA@^Fz z6t^q6QqphQt`?$~&X|LUYvE)~@V-j6LI%2^hV3PU(WcR^-iDG7En} zsWgFMOJaD!hMe=O`{>C-n{+!@IItnY`)k`txB{u*@QYQxaNPzTt@x3W_ntqzq=HfM z;1%%#Tn5rJ#5X6LS1I81TA+$BZm>%7STKG=0gm*OkIBR_%(p__@FPb!05)ji!Y0vn9^e=gaY@^YwMLsNurf}_NFE$vP(zIKduJk zHvu5e@&Z+6)}WnYjr1#ioM&Q}eH*#7m_nWyUDDTm)Ia6s(;!mW{2i;?7(FobA{r8k z5bpgLyE?r6FulatKWjT4*5-f3QGQg#gFpIps=DKw{cVp3aburpu9rLbQ4H!{PmxZL zDuC2ash?E=9eL!2u9MNmnGnl}`c);8SI2eT!{2_m2*UZ07x))~TIw(I<2t1x=;Rpd z=NDiSx|aU08g#pE4?4iHWnk5Yp;b0>A71gz%+bT-Nosv87s!So2*jBVH&5uVfNket?v9oro>|;J3{tg;cZ`-cNPeH~otsu{0BJq~4{B32s5JG+c{ZA* z1oau7^9fr`9OUV13aHW8EYgylkYI0vqt1X?xRnMOZ#Z45ZMmL78 z=P&mmcgM&m44-@g4>o4iAur5k##Hki=i+(u@hxfeZEmhFzHqPsE6tYpGcDb1@lCCH zIZG!&tOYWC9z)W@R;@#ihl#@w;bZD@(f5x>;)X@MHx(=|_r(zP zIiZls>kkvhzHCm4f}fYgJqbFmX8mE!JFxoc05|_I`f=+6*y!g7tQglvBATR7sp26X zP4_{)xzAKzpVbN$M162++;~G`-FLPd#kPO_UxTXcY)aJzf$*iRkci~8!j%yx+49O} zqlMPGp|W^ZgpDwwM89SzzcZQS%f1MGKha&}z)wnH^C3|aS|3$%$^;xRE zwSvr~-tSH&Q07Z!V4Q_}%S$Z|){xK`|eNDQXtH1pTe42KLBQV7Ek3>07)32%SCCnTzAUk_*zikb6gGsvNHTW_dbL*Pce_1WepEUMlYM5lO>A~L$5 z=Hjk1Te+jgsmj|G2EI$Fe7XDUi<|y>0)Z2q#0YRK*L{IwymH%DLq^-E8Ma%|YK&B&_Vi$K zzR?>6iRJu;slo}#QkYt(3l`SBYId@ps2@d&*yk+$$`l>q&B-#YvyE)tDXyO!yc4iq zl5qPcc}}sW;m&EoS*F%$2-`ibG)y>YyGb2}gYO-sDMo(mT6+ zA6e{b?!VNSq_^QO@%%qvtybSpbDQvv$4d8k7_pY)!RG9@{7cy^sRekeSG?tk{omWC zoodn(PX<>Ck9kg>cJjVqH8XrELkrw2aK2dy&l&bO+8?J|{Df3mbOqK^jyZwVt3_^T zz<6;?VUn#7HbbsZpD6V`u-@W#;%aG&)`jktZ*XpIurEzlsBsvi04EH5)7jQFZCZ`X zcw_GA&(I#&rF0B)RCipD`qrVIoygp}24Pd@x@09W%BjIN<{*mKiwl33m9%Kfq;?xH zr*x*8LFqIV|B-ls|5CyUP{lRfjCr)t6_#5w{82ypFY2}e7XvXzEo!oJBsdi6VdgT; zD5flhBku92&6>Me7;vE>bm#l^VKl-*otOB~8rQWen5N0(sO=~DL8YojI79p4+$S8z zuAx13t-|vD3xMNv`-a?r+faOs5d;dguQDA%VDbyjM-qSQkWQrRSC3Dw6)(0057v?F z?REAME$on?oXgQeos5ml3(8Wt-4(|(h`)xc{a@Xlqz1l;Qv)_|iZVIE5WX>Ptc@2K z=(=a`_77U<0i7c&{-k+HzeMcafD2RQyd5h`Mmg6DgSqGeD|d#I3*4Q8Uq_~sClr3> zTprmhjc)m%(kF8s=m-*q{JO<)3?JD-IH@UJQQZ@#)ul2Np9<{)Ye1})uZLnkeculow+S!>_&J0*%gQ5VP2DCIPavz z@pl2Ir)q1m$unFH=Yb4Ci5Fg9tbYAJp($M6423Uy^ zUWVD~_v_+6k;WSJyq43+`cX4@K5+7SQ)%Uv;Fg#Cny9vt`>xPgm}y4vWF>5>`TZ*G zovULaQMO;iHN1=f=+3 z*QGsP9;oFKnt26M-X$BD`;oYDH2JD8>G~Pl#|i2tUnN~9rJHY) zh-pS*We~QfTo=kpd;>*3m^>D+iL4f-!uEKg{6|Kocee#=XJr_Z9 z(-b5|c&Z)f!{DMWfmc+boiVPjE9({?*1$mG|CD(^3|Y zs5!DkX0y&|(Jjc;Z{I$Wzkb;;mD0RL`JL<0IT#vNg4*!2m-Dh>%o}P7a1U{`=Xp~ap}lL(N$ZHC6!Xuo)Oum??ti5{+8$Ma|ldM*$N>091n!c!mWiVQ+A2D3tUop2XL)c8YYHA6tHQtjm-r-EZTf}+} zgz3CC)D+xKJPZ;j;TgWE$LUsPP8Vq$9_M1?1G81i@12coO}Is6?*D30EgwL6?Ff%^ zkB?@XZ_&U*iLQwCHNlA;4hVD9JZr4lq+WJIjg@0sm+=Z$%=;33!)t#nx0e3+J50`i zA#e{X;7~}r;J7t#^YY4a;<0tuhpQnwXlHo!9*;io8;udWRv!waCiXv%aoL0Z3s(@6{$Y&kw+^W3k zY|McP@m}4|sA4rLVXte|uXnLuo90Pu9(WSRgfH@sr26ZOGlQPanxuBAVZY?G^f-ja zLms<%qZAp0*z4eg32aje!EsPigW003*Uy$CFSkR^NiahmHJee6?!=G4=N9Zvoe!IG z;XEx6`;Hpi?_t@&%L}8SH}fCOST73PoJ$>h0c6615=`kZM#Fh26wH=&z>N&b=qTyM ziH_mR9rgJ-)8%bt1)5Z}MRie$mR~J}n)s6K^%DYbbFaQG;v3|fs+~u3P(hsN86ChE*eW%t*jzf|)iW>q! zyD|ncWkOllFwtPa9vK>$|S1`Dl|kp z+T3B-s@rMGc;(ls!}YNDOWEZ?CAT%)U+zBmuLEd|PaPOF@=grX1U-ABx1p6nLif_Q z2={$5jV4!2v%laFvLM(R1P4FRL!liU@FD!)IQ!Ng6o<1UN^ZH2Hw>Fw`WVMl-mGN@ z@0iG6J|aa{VGHIw%@><~=@z9!xF$~fdf|At_J6eRzIy4b!>g$2=HK`ux35SLh#A27}nzh&|=OnZ>D~qIYi@Nfao6fs|HPR5V zE;5!-6aI11S~pv4>Rg!N`HN8pT>K-8#;@q_Q_zjl4ik86>rlE@Vc6%r8{GD6QPduE}D~kSzpq`CuNJJ;qdTym<3E8 zy62=2qSpN?Ep4)w7b~;!Rz)E7Cm{{x6RG===fD0}Q|E+@L8&WXIX>fekr2Y_94SbB zcqIw3?eDVf1($mCT6*l4Pj(BboP?Gi&1unTSsYm0l}>K2@|`VwBA-LIn1(m+LEnYK(q1pQjh4$+H*!1+-gRsa)_Ts zZVYw zq+dzM&K=Y`mU8JI45M##pB7OQshHd~%Ui#dko|$<`XSKI4LO@VD1wTZm73Zo2j&}8 zg?EnB3w?2nH+3$&o8-3@og4-Cj)|jV5rcjS_epwJo;09fxf!8UsS*?)k>O{?R9fjd ztd!7CRmJx-;#^Y8e$3{Q+%>p$vd>M&ZUd7@NwNA#=UTAO1qO3FA*+ZK9&qk~ zvW{XhV3TbHHj*nB48UL>KKY@FPSuZeO9akK&dNpjF0>#K)WKv*-RaIysr8!Xqnb%q zgV<|5A9G}DvxtZW+btnZ`vm3;Oy%)=+oRrEhht>m~t1SoG51x__amtxKA zG*Srz6x^Uz{HAJz(%0_w5iwJo*|CuhN&;s}ffO4~*G9eT{&{V40(NaUWaB_RnyWs`@OClUWOyxV8A#hb|jCH1Jiuz!Y`6t{=qqIh-};G92p|c!lJ=96wDC; zMED`~eb>b1o-3U^LdhZvfZO}m@4i0k;*RALiAw8uW0WHJ2n14f zEm&d~nHT9Mg$N2mk8paiPJg-!j__Nw`E=&)7Ds`X=y+QBFHiJO>Sx}#xjtdMz_G!J zBCBQ{Bgbqi_Fi38{BYn<@DQnF*LVw_W;7DyDKSP9Kpv_oMlM?%vnvqg;P)`h=Aqi*aoXq(<&j8fVe$*; zS15e2*4>97qx+n3==j{MdeWU?6NhE6OythY{ z#c6x`4IRGYpAcdzw-vT7xAf)gTy>~gemCrO&p(S7*7L3Is|Yi=NI4W`Of?GX!Yotb zH*s0J4$HV~z^#a19#I`!2;O(iRrbU+YXy6)2IF@$ls44EEt`!$+&GSBa$a(}mf54r zW_zx38CBFzMv|Q(*U~J!p3c^K7q=PaCJ^S`IRdyMuSLI(Q=i#mZ?PVlcjGhkMT^Ba z;Koe;!9u{E%WBZ`*_-+7?#pmt9`-$sw%*%i8Ot?2`+WluGUMvHH2A>XBgv#;JE%JR z%ZEz4(EA#7Tutxrgk8YS}A@U*81RS!xrxTFxQ$^ z7{W`77Q?>tyZ7hU*(AhMB=Yw7G@VD@AX%0vDg%*02@Pnsuwix>AhF5=pEImy{~O<%l29i@f# zM7yRo+Sl$F4!#J2a=HX23+nKho^1hvytbwk=dlrIWI4Z`6!v@$D{<7|c?P(%&x-k4 ztjJfgZu@yS50vlco6M-{MEPC|27yvbZ#d3@@>+d|P>25$Fn9LYk$QE+mU%lp>`jjB zhs>#`TQf03#?FOj=pF$FC%mlbax)LQlf~(41RM3Xtcd?76dzUh+9Q8a^9u3TyfVF~ zXuD?^_9&kueGr1ZfPbqb97+r7 z!$=FTJFq!t=>c2kB9e}RGI6usaTZablZPPBm-TpDQewVtTZ zE~IjyEUWVASrge<3wP1~rJf;W4sycD^)S#xqzOX4Q9Lr{Pe#QDsQ=Husdikc}9;16V<^LE6FR6W=T@1N9-+_*of z8<@zgG*}#uQkvpnU{~WWMw4V2+q*t2JW*j=ki_F? z?{oRo-wY4AzZo7&26Y$^O6NyC2$hu6V4(K=!Q@}IXz>0aM=oWK8`|Fu^!a1fStpXE z+H)FLV%V?BRw>gmQM`uos9u@(&rHcNp!)>u0t#f<{?gI^hYp~QGIU=?Jr1_s$9MV6 zUjm%|5CA+)$Y5LJY&jz1eIBC0&Sw|*N3i>}|Kyl_SFPFYSB>L`VUF@R3h9L@3Nin~ zurR(i#i^M%J<*RxK~G2DL@`P!*(E!>aqFIZ1bo|DM;-k;aeq!_%52Kf)?TTy4}fV7 z0zI?(o7V-%#YtMlLGeFGt)cx?7NHI1L76*7lb(Z8LleY@HiHjPFiOWgJ$cae_ii*mKiXQKx-~XQ;fV$Z@+WGzOAMlH>1Frr7 rG1K1g)W%NE$kxNt(ajZfPeoNoOjyc5+O!_125H>YRYBc;^x}U2%#xcF literal 0 HcmV?d00001 From d5d5daf87a3e0e83b62cf33bd9c27dccc37e6415 Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Sat, 5 Oct 2019 11:17:29 +0200 Subject: [PATCH 3/8] first draft of Counting Kata --- Counting/ReferenceImplementation.qs | 157 ++++++---------------------- Counting/TestSuiteRunner.cs | 4 +- Counting/Tests.qs | 30 +----- 3 files changed, 39 insertions(+), 152 deletions(-) diff --git a/Counting/ReferenceImplementation.qs b/Counting/ReferenceImplementation.qs index 870ba585ad8..4e793addf3e 100644 --- a/Counting/ReferenceImplementation.qs +++ b/Counting/ReferenceImplementation.qs @@ -24,54 +24,20 @@ namespace Quantum.Kata.Counting { // Part I. Oracle for Counting ////////////////////////////////////////////////////////////////// - // Task 1.1. The Sprinkler oracle - // Let us consider an example inspired by the sprinkler problem of (Pearl 1988): - // we have three Boolean variable, s, r, w representing respectively propositions - // “the sprinkler was on”, "ıt rained last night” and “the grass is wet”. - // We know that if the sprinkler was on the grass is wet (s → w), - // if it rained last night the grass is wet (r → w) - //and that the the sprinkler being on and rain last night cannot be true at the same time (s, r →). - // Transformed in conjunctive normal formal we obtain formula (¬s ∨ w) ∧ (¬r ∨ w) ∧ (¬s ∨ ¬r) - // Let s,r,w=queryRegister[0],queryRegister[1],queryRegister[2] - operation Oracle_Sprinkler_Reference (queryRegister : Qubit[], target : Qubit, ancilla : Qubit[]) : Unit - { - body (...) { - X(queryRegister[2]); - X(ancilla[0]); - X(ancilla[1]); - X(ancilla[2]); - - CCNOT(queryRegister[0],queryRegister[1],ancilla[0]); - CCNOT(queryRegister[1],queryRegister[2],ancilla[1]); - CCNOT(queryRegister[0],queryRegister[2],ancilla[2]); - (Controlled X)([ancilla[0],ancilla[1],ancilla[2]],target); - CCNOT(queryRegister[0],queryRegister[2],ancilla[2]); - CCNOT(queryRegister[1],queryRegister[2],ancilla[1]); - CCNOT(queryRegister[0],queryRegister[1],ancilla[0]); - - X(ancilla[2]); - X(ancilla[1]); - X(ancilla[0]); - } - adjoint invert; - controlled auto; - controlled adjoint auto; - } - - - - - // Arbitrary bit pattern oracle - operation Oracle_ArbitraryPattern_Reference (queryRegister : Qubit[], target : Qubit, pattern : Bool[]) : Unit - is Adj+Ctl { - (ControlledOnBitString(pattern, X))(queryRegister, target); - } - + operation Oracle_SolutionCount_Reference (queryRegister : Qubit[], target : Qubit, nSol : Int) : Unit is Ctl+ Adj { + // Designate first nSol integers solutions (since we don't really care which ones are solutions) + for (i in 0 .. nSol - 1) { + (ControlledOnInt(i, X))(queryRegister, target); + } + } - // Oracle converter - operation OracleConverterImpl (markingOracle : ((Qubit[], Qubit) => Unit is Adj+Ctl), register : Qubit[]) : Unit - is Adj+Ctl { - + ////////////////////////////////////////////////////////////////// + // Part II. The Grover iteration + ////////////////////////////////////////////////////////////////// + + + // Helper operation which converts marking oracle into phase oracle using an extra qubit + operation ApplyMarkingOracleAsPhaseOracle (markingOracle : ((Qubit[], Qubit) => Unit is Ctl+Adj), register : Qubit[]) : Unit is Adj+Ctl { using (target = Qubit()) { // Put the target into the |-⟩ state X(target); @@ -87,63 +53,18 @@ namespace Quantum.Kata.Counting { } } - - function OracleConverter (markingOracle : ((Qubit[], Qubit) => Unit is Adj+Ctl)) : (Qubit[] => Unit is Adj+Ctl) { - return OracleConverterImpl(markingOracle, _); - } - - - ////////////////////////////////////////////////////////////////// - // Part II. The Grover iteration - ////////////////////////////////////////////////////////////////// - - // The Hadamard transform - operation HadamardTransform (register : Qubit[]) : Unit - is Adj+Ctl { - - // ApplyToEachA(H, register); - - // ApplyToEach is a library routine that is equivalent to the following code: - let nQubits = Length(register); - for (idxQubit in 0..nQubits - 1) { - H(register[idxQubit]); - } - } - - - // Conditional phase flip - operation ConditionalPhaseFlip (register : Qubit[]) : Unit { - - body (...) { - // Define a marking oracle which detects an all zero state - let allZerosOracle = Oracle_ArbitraryPattern_Reference(_, _, new Bool[Length(register)]); - - // Convert it into a phase-flip oracle and apply it - let flipOracle = OracleConverter(allZerosOracle); - flipOracle(register); - R(PauliI, 2.0 * PI(), register[0]); - } - - adjoint self; - controlled auto; - controlled adjoint auto; - } - - - - // The Grover iteration - operation GroverIteration (register : Qubit[], oracle : (Qubit[] => Unit is Adj+Ctl)) : Unit + operation GroverIteration (register : Qubit[], oracle : ((Qubit[],Qubit) => Unit is Ctl+Adj)) : Unit is Ctl+Adj { - body (...) { - oracle(register); - HadamardTransform(register); - ConditionalPhaseFlip(register); - HadamardTransform(register); - } - adjoint auto; - controlled auto; - controlled adjoint auto; + + // apply oracle + ApplyMarkingOracleAsPhaseOracle(oracle, register); + // apply inversion about the mean + ApplyToEachCA(H, register); + ApplyToEachCA(X, register); + Controlled Z(Most(register), Tail(register)); + ApplyToEachCA(X, register); + ApplyToEachCA(H, register); } @@ -151,38 +72,24 @@ namespace Quantum.Kata.Counting { // Part III. Putting it all together: Quantum Counting ////////////////////////////////////////////////////////////////// - operation UnitaryPowerImpl (U : (Qubit[] => Unit is Adj+Ctl), power : Int, q : Qubit[]) : Unit { - body (...) { - for (i in 1..power) { - U(q); - } - } - adjoint auto; - controlled auto; - controlled adjoint auto; - } - operation Counting_Reference() : Double { + operation Counting_Reference(n_bit : Int, n_sol: Int, precision: Int) : Double { mutable phase = -1.0; - let n=4; - using ((reg,phaseRegister,ancilla)=(Qubit[3],Qubit[n],Qubit[3])) - { - // Construct a phase estimation oracle from the unitary - let phaseOracle = OracleConverter(Oracle_Sprinkler_Reference(_,_,ancilla)); - let oracle = DiscreteOracle(UnitaryPowerImpl(GroverIteration(_, phaseOracle), _, _)); + using ((reg,phaseRegister)=(Qubit[n_bit],Qubit[precision])) + { + let oracle = OracleToDiscrete(GroverIteration(_, Oracle_SolutionCount_Reference(_,_,n_sol))); // Allocate qubits to hold the eigenstate of U and the phase in a big endian register let phaseRegisterBE = BigEndian(phaseRegister); // Prepare the eigenstate of U - HadamardTransform(reg); -//should return 0.5 + ApplyToEach(H, reg); // Call library QuantumPhaseEstimation(oracle, reg, phaseRegisterBE); // Read out the phase - set phase = IntAsDouble(MeasureInteger(BigEndianAsLittleEndian(phaseRegisterBE))) / IntAsDouble(1 <<< (n)); + set phase = IntAsDouble(MeasureInteger(BigEndianAsLittleEndian(phaseRegisterBE))) / IntAsDouble(1 <<< (n_bit)); ResetAll(reg); ResetAll(phaseRegister); @@ -190,8 +97,10 @@ namespace Quantum.Kata.Counting { let angle = PI()*phase; let res = (PowD(Sin(angle),2.0)); - return 8.0*res; + return PowD(2.0,IntAsDouble(n_bit))*res; } - + operation CR(): Double { + return Counting_Reference(4, 4, 3); + } } diff --git a/Counting/TestSuiteRunner.cs b/Counting/TestSuiteRunner.cs index 7a412664557..12ba97b04a9 100644 --- a/Counting/TestSuiteRunner.cs +++ b/Counting/TestSuiteRunner.cs @@ -12,7 +12,7 @@ using Xunit.Abstractions; using System.Diagnostics; -namespace Quantum.Kata.GroversAlgorithm +namespace Quantum.Kata.Counting { public class TestSuiteRunner { @@ -25,7 +25,7 @@ public TestSuiteRunner(ITestOutputHelper output) /// /// This driver will run all Q# tests (operations named "...Test") - /// that belong to namespace Quantum.Kata.GroversAlgorithm. + /// that belong to namespace Quantum.Kata.Counting. /// [OperationDriver(TestNamespace = "Quantum.Kata.Counting")] public void TestTarget(TestOperation op) diff --git a/Counting/Tests.qs b/Counting/Tests.qs index 55713b8e636..f49e290a9c6 100644 --- a/Counting/Tests.qs +++ b/Counting/Tests.qs @@ -14,39 +14,17 @@ namespace Quantum.Kata.Counting { open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Math; + open Microsoft.Quantum.Intrinsic; - // ------------------------------------------------------ - // helper wrapper to represent oracle operation on input and output registers as an operation on an array of qubits - operation QubitArrayWrapperOperation (op : ((Qubit[], Qubit, Qubit[]) => Unit is Adj), qs : Qubit[]) : Unit - is Adj { - let reg= Partitioned([3,1],qs); - op(reg[0], reg[1][0], reg[2]); - } - - - // ------------------------------------------------------ - // helper wrapper to test for operation equality on various register sizes - operation AssertRegisterOperationsEqual (testOp : (Qubit[] => Unit), refOp : (Qubit[] => Unit is Adj)) : Unit { - AssertOperationsEqualReferenced(7, testOp, refOp); - } - - - // ------------------------------------------------------ - - operation T11_Oracle_Sprinkler_Test () : Unit { - let testOp = QubitArrayWrapperOperation(Oracle_Sprinkler, _); - let refOp = QubitArrayWrapperOperation(Oracle_Sprinkler_Reference, _); - AssertRegisterOperationsEqual(testOp, refOp); - } - // ------------------------------------------------------ - operation T21_Counting_Test () : Unit { - let reference=Counting(); + operation T11_Counting_Test () : Unit { + let reference=Counting_Reference(4,4,3); +// Message(DoubleAsString(reference)); let actual=4.0; EqualityWithinToleranceFact(reference,actual,3.0); } From 2c655c7c6dad4910ad0f078af8169ecbdb6a0c20 Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Sat, 5 Oct 2019 20:06:29 +0200 Subject: [PATCH 4/8] added a /2 factor to angle, still not working --- Counting/ReferenceImplementation.qs | 15 ++++++++++----- Counting/Tests.qs | 9 +++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Counting/ReferenceImplementation.qs b/Counting/ReferenceImplementation.qs index 4e793addf3e..063b21ee361 100644 --- a/Counting/ReferenceImplementation.qs +++ b/Counting/ReferenceImplementation.qs @@ -67,7 +67,12 @@ namespace Quantum.Kata.Counting { ApplyToEachCA(H, register); } - + operation UnitaryPowerImpl (U : (Qubit[] => Unit is Adj+Ctl), power : Int, q : Qubit[]) : Unit is Ctl+Adj + { + for (i in 1..power) { + U(q); + } + } ////////////////////////////////////////////////////////////////// // Part III. Putting it all together: Quantum Counting ////////////////////////////////////////////////////////////////// @@ -80,6 +85,9 @@ namespace Quantum.Kata.Counting { { let oracle = OracleToDiscrete(GroverIteration(_, Oracle_SolutionCount_Reference(_,_,n_sol))); + // let phaseOracle = Oracle_SolutionCount_Reference(_,_,n_sol); + +// let oracle = DiscreteOracle(UnitaryPowerImpl(GroverIteration(_, phaseOracle), _, _)); // Allocate qubits to hold the eigenstate of U and the phase in a big endian register @@ -95,12 +103,9 @@ namespace Quantum.Kata.Counting { ResetAll(phaseRegister); } let angle = PI()*phase; - let res = (PowD(Sin(angle),2.0)); + let res = (PowD(Sin(angle/2.0),2.0)); return PowD(2.0,IntAsDouble(n_bit))*res; } - operation CR(): Double { - return Counting_Reference(4, 4, 3); - } } diff --git a/Counting/Tests.qs b/Counting/Tests.qs index f49e290a9c6..3d746925486 100644 --- a/Counting/Tests.qs +++ b/Counting/Tests.qs @@ -23,10 +23,11 @@ namespace Quantum.Kata.Counting { // ------------------------------------------------------ operation T11_Counting_Test () : Unit { - let reference=Counting_Reference(4,4,3); -// Message(DoubleAsString(reference)); - let actual=4.0; - EqualityWithinToleranceFact(reference,actual,3.0); + let n_sol=8; + let reference=Counting_Reference(6,n_sol,6); + Message(DoubleAsString(reference)); + + EqualityWithinToleranceFact(reference,IntAsDouble(n_sol),3.0); } } From 2774714db0d28137b5bbfe25d902709e1096f694 Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Tue, 8 Oct 2019 08:30:44 +0200 Subject: [PATCH 5/8] fixed a bug in phase computation --- Counting/ReferenceImplementation.qs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Counting/ReferenceImplementation.qs b/Counting/ReferenceImplementation.qs index 063b21ee361..110416a4b04 100644 --- a/Counting/ReferenceImplementation.qs +++ b/Counting/ReferenceImplementation.qs @@ -97,7 +97,7 @@ namespace Quantum.Kata.Counting { // Call library QuantumPhaseEstimation(oracle, reg, phaseRegisterBE); // Read out the phase - set phase = IntAsDouble(MeasureInteger(BigEndianAsLittleEndian(phaseRegisterBE))) / IntAsDouble(1 <<< (n_bit)); + set phase = IntAsDouble(MeasureInteger(BigEndianAsLittleEndian(phaseRegisterBE))) / IntAsDouble(1 <<< (precision)); ResetAll(reg); ResetAll(phaseRegister); From bb2de0b313f743100455b457a8b4c222c37838df Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Wed, 9 Oct 2019 18:02:41 +0200 Subject: [PATCH 6/8] Counting working by adding a global phase to conditional phase flip. 3 tests with different number of solutions: 16, 20, 40 --- Counting/ReferenceImplementation.qs | 5 ++-- Counting/Tests.qs | 45 +++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Counting/ReferenceImplementation.qs b/Counting/ReferenceImplementation.qs index 110416a4b04..f310c157a81 100644 --- a/Counting/ReferenceImplementation.qs +++ b/Counting/ReferenceImplementation.qs @@ -64,6 +64,7 @@ namespace Quantum.Kata.Counting { ApplyToEachCA(X, register); Controlled Z(Most(register), Tail(register)); ApplyToEachCA(X, register); + R(PauliI, 2.0 * PI(), register[0]); ApplyToEachCA(H, register); } @@ -93,7 +94,7 @@ namespace Quantum.Kata.Counting { let phaseRegisterBE = BigEndian(phaseRegister); // Prepare the eigenstate of U - ApplyToEach(H, reg); + ApplyToEach(H, reg); // Call library QuantumPhaseEstimation(oracle, reg, phaseRegisterBE); // Read out the phase @@ -103,7 +104,7 @@ namespace Quantum.Kata.Counting { ResetAll(phaseRegister); } let angle = PI()*phase; - let res = (PowD(Sin(angle/2.0),2.0)); + let res = (PowD(Sin(angle),2.0)); return PowD(2.0,IntAsDouble(n_bit))*res; } diff --git a/Counting/Tests.qs b/Counting/Tests.qs index 3d746925486..0c4a7a6ced1 100644 --- a/Counting/Tests.qs +++ b/Counting/Tests.qs @@ -17,17 +17,50 @@ namespace Quantum.Kata.Counting { open Microsoft.Quantum.Intrinsic; + operation Compute_Average(n_bit : Int, n_sol: Int, precision: Int, iterations: Int, tolerance_fraction: Double): Unit + { + mutable sum=0.0; + let tolerance=tolerance_fraction*IntAsDouble(n_sol); + + for (i in 1..iterations) + { + let reference=Counting_Reference(n_bit,n_sol,precision); + Message(DoubleAsString(reference)); + set sum=sum+reference; + } + let average=sum/IntAsDouble(iterations); + Message("Expected :"+IntAsString(n_sol)+" Found (average): "+DoubleAsString(average)); + EqualityWithinToleranceFact(average,IntAsDouble(n_sol),tolerance); + } // ------------------------------------------------------ - operation T11_Counting_Test () : Unit { - let n_sol=8; - let reference=Counting_Reference(6,n_sol,6); - Message(DoubleAsString(reference)); + operation T7_16_5_Counting_Test () : Unit { + let iterations=10; + let n_bit=7; + let n_sol=16; + let precision=5; + let tolerance_fraction=0.7; + Compute_Average(n_bit,n_sol,precision,iterations,tolerance_fraction); + } - EqualityWithinToleranceFact(reference,IntAsDouble(n_sol),3.0); + operation T7_20_5_Counting_Test () : Unit { + let iterations=10; + let n_bit=7; + let n_sol=20; + let precision=5; + let tolerance_fraction=0.7; + Compute_Average(n_bit,n_sol,precision,iterations,tolerance_fraction); + } + + operation T7_40_5_Counting_Test () : Unit { + let iterations=10; + let n_bit=7; + let n_sol=40; + let precision=5; + let tolerance_fraction=0.7; + Compute_Average(n_bit,n_sol,precision,iterations,tolerance_fraction); } - } From 3c02e2e835f6c1839ba225094d6ca23dcdae01e0 Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Thu, 10 Oct 2019 09:45:13 +0200 Subject: [PATCH 7/8] fixed tasks to guide user devel --- Counting/ReferenceImplementation.qs | 25 +++++++--------------- Counting/Tasks.qs | 33 +++++++---------------------- Counting/Tests.qs | 2 +- 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/Counting/ReferenceImplementation.qs b/Counting/ReferenceImplementation.qs index f310c157a81..9657b5ac147 100644 --- a/Counting/ReferenceImplementation.qs +++ b/Counting/ReferenceImplementation.qs @@ -24,7 +24,7 @@ namespace Quantum.Kata.Counting { // Part I. Oracle for Counting ////////////////////////////////////////////////////////////////// - operation Oracle_SolutionCount_Reference (queryRegister : Qubit[], target : Qubit, nSol : Int) : Unit is Ctl+ Adj { + operation Oracle_Solution_Count_Reference (queryRegister : Qubit[], target : Qubit, nSol : Int) : Unit is Ctl+ Adj { // Designate first nSol integers solutions (since we don't really care which ones are solutions) for (i in 0 .. nSol - 1) { (ControlledOnInt(i, X))(queryRegister, target); @@ -68,12 +68,7 @@ namespace Quantum.Kata.Counting { ApplyToEachCA(H, register); } - operation UnitaryPowerImpl (U : (Qubit[] => Unit is Adj+Ctl), power : Int, q : Qubit[]) : Unit is Ctl+Adj - { - for (i in 1..power) { - U(q); - } - } + ////////////////////////////////////////////////////////////////// // Part III. Putting it all together: Quantum Counting ////////////////////////////////////////////////////////////////// @@ -82,25 +77,21 @@ namespace Quantum.Kata.Counting { operation Counting_Reference(n_bit : Int, n_sol: Int, precision: Int) : Double { mutable phase = -1.0; - using ((reg,phaseRegister)=(Qubit[n_bit],Qubit[precision])) + using ((register,phaseRegister)=(Qubit[n_bit],Qubit[precision])) + // Allocate qubits to hold the eigenstate of U and the phase in a big endian register { - let oracle = OracleToDiscrete(GroverIteration(_, Oracle_SolutionCount_Reference(_,_,n_sol))); - - // let phaseOracle = Oracle_SolutionCount_Reference(_,_,n_sol); + let oracle = OracleToDiscrete(GroverIteration(_, Oracle_Solution_Count_Reference(_,_,n_sol))); -// let oracle = DiscreteOracle(UnitaryPowerImpl(GroverIteration(_, phaseOracle), _, _)); - - // Allocate qubits to hold the eigenstate of U and the phase in a big endian register let phaseRegisterBE = BigEndian(phaseRegister); // Prepare the eigenstate of U - ApplyToEach(H, reg); + ApplyToEach(H, register); // Call library - QuantumPhaseEstimation(oracle, reg, phaseRegisterBE); + QuantumPhaseEstimation(oracle, register, phaseRegisterBE); // Read out the phase set phase = IntAsDouble(MeasureInteger(BigEndianAsLittleEndian(phaseRegisterBE))) / IntAsDouble(1 <<< (precision)); - ResetAll(reg); + ResetAll(register); ResetAll(phaseRegister); } let angle = PI()*phase; diff --git a/Counting/Tasks.qs b/Counting/Tasks.qs index 3f42bd2a12c..4920f2d913c 100644 --- a/Counting/Tasks.qs +++ b/Counting/Tasks.qs @@ -36,40 +36,23 @@ namespace Quantum.Kata.Counting { // Part I. Oracle for Counting ////////////////////////////////////////////////////////////////// - // Task 1.1. The Sprinkler oracle - // Let us consider an example inspired by the sprinkler problem of (Pearl 1988): - // we have three Boolean variable, s, r, w representing respectively propositions - // “the sprinkler was on”, "ıt rained last night” and “the grass is wet”. - // We know that if the sprinkler was on the grass is wet (s → w), - // if it rained last night the grass is wet (r → w) - // and that the the sprinkler being on and rain last night cannot be true at the same time (s, r →). - // Transformed in conjunctive normal formal we obtain formula (¬s ∨ w) ∧ (¬r ∨ w) ∧ (¬s ∨ ¬r) - // Let s,r,w=queryRegister[0],queryRegister[1],queryRegister[2] - // Hint: to solve this task you also need to use ancilla qubits - // This formula has 4 models out of 8 possible worlds + // Task 1.1. The solution count oracle + // Designate first nSol integers solutions (since we don't really care which ones are solutions) - operation Oracle_Sprinkler (queryRegister : Qubit[], target : Qubit, ancilla : Qubit[]) : Unit - { - body (...) { - // ... - } - adjoint invert; - controlled auto; - controlled adjoint auto; - } + operation Oracle_Solution_Count (queryRegister : Qubit[], target : Qubit, nSol : Int) : Unit is Ctl+ Adj { + // + } ////////////////////////////////////////////////////////////////// // Part I. Counting ////////////////////////////////////////////////////////////////// // Implement counting using operations from ReferenceImplementation.qs - // - UnitaryPowerImpl, for computing powers of a unitary operation // - GroverIteration for the Grover operator // - QuantumPhaseEstimation, for estimating the phase - // Counting should return the number of models, 4 in this case - operation Counting() : Double { - + // Counting should return the number of models, n_sol + operation Counting(n_bit : Int, n_sol: Int, precision: Int) : Double { // .... - return 4.0; + return 0.0; } diff --git a/Counting/Tests.qs b/Counting/Tests.qs index 0c4a7a6ced1..9d884c23583 100644 --- a/Counting/Tests.qs +++ b/Counting/Tests.qs @@ -24,7 +24,7 @@ namespace Quantum.Kata.Counting { for (i in 1..iterations) { - let reference=Counting_Reference(n_bit,n_sol,precision); + let reference=Counting(n_bit,n_sol,precision); Message(DoubleAsString(reference)); set sum=sum+reference; } From 349c1137c03b2a5e50d7f569dbaa49a066f1c20b Mon Sep 17 00:00:00 2001 From: Fabrizio Riguzzi Date: Thu, 10 Oct 2019 19:03:02 +0200 Subject: [PATCH 8/8] signature of operations in comments --- Counting/Tasks.qs | 6 ++++-- Counting/Tests.qs | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Counting/Tasks.qs b/Counting/Tasks.qs index 4920f2d913c..4bc634ffcfb 100644 --- a/Counting/Tasks.qs +++ b/Counting/Tasks.qs @@ -47,8 +47,10 @@ namespace Quantum.Kata.Counting { // Part I. Counting ////////////////////////////////////////////////////////////////// // Implement counting using operations from ReferenceImplementation.qs - // - GroverIteration for the Grover operator - // - QuantumPhaseEstimation, for estimating the phase + // - GroverIteration (register : Qubit[], oracle : ((Qubit[],Qubit) => Unit is Ctl+Adj)) : Unit is Ctl+Ad + // for the Grover operator + // - QuantumPhaseEstimation (oracle : Microsoft.Quantum.Oracles.DiscreteOracle, targetState : Qubit[], controlRegister : Microsoft.Quantum.Arithmetic.BigEndian) : Unit + // from Microsoft.Quantum.Characterization, for estimating the phase // Counting should return the number of models, n_sol operation Counting(n_bit : Int, n_sol: Int, precision: Int) : Double { // .... diff --git a/Counting/Tests.qs b/Counting/Tests.qs index 9d884c23583..ab6e7630c92 100644 --- a/Counting/Tests.qs +++ b/Counting/Tests.qs @@ -32,9 +32,6 @@ namespace Quantum.Kata.Counting { Message("Expected :"+IntAsString(n_sol)+" Found (average): "+DoubleAsString(average)); EqualityWithinToleranceFact(average,IntAsDouble(n_sol),tolerance); } - - - // ------------------------------------------------------ operation T7_16_5_Counting_Test () : Unit {