# Exercise – Use the Quantum Development Kit to create Q# applications for Azure Quantum

Now let's see how you can use Azure Quantum to test quantum algorithms, first on a simulator and then on real hardware.

If you took a previous module of this learning path, you created a version of Grover's algorithm in Q# and ran it on a local simulator. Now let's run the same algorithm in a trapped ion quantum computer.

## Create the Q# project for IonQ

Use Visual Studio Code to create a Q# Project.

In Visual Studio Code, open the

**View**menu, and select**Command Palette**.Enter

**Q#: Create New Project**.Select

**Quantum application targeted to IonQ backend**.Select a directory to hold your project, such as your home directory, and name your project. For example, enter

**MyGroversJob**as the project name, and select**Create Project**.From the window that appears at the bottom, select

**Open new project**.You should see two files: the project file and

*Program.qs*, which contains starter code.

## Adapt Grover's algorithm to run in hardware

Fortunately, you don't need control flow features to implement the basic variant of Grover's algorithm, so you can easily adapt the Q# code of previous modules to run on IonQ's targets.

For the moment, we have a limited number of qubits available, so you'll run a simple version of Grover's algorithm.

### Write the core part of Grover's algorithm

Open the file *Program.qs*, and add the following content:

First, add the Grover's diffusion operation:

`operation ReflectAboutUniform(inputQubits : Qubit[]) : Unit { within { ApplyToEachCA(H, inputQubits); ApplyToEachCA(X, inputQubits); } apply { Controlled Z(Most(inputQubits), Tail(inputQubits)); } }`

Now, write the full Grover's search operation that takes a phase oracle as input:

`operation RunGroversSearch(register : Qubit[], phaseOracle : ((Qubit[]) => Unit is Adj), iterations : Int) : Unit { ApplyToEachCA(H, register); for _ in 1 .. iterations { phaseOracle(register); ReflectAboutUniform(register); } }`

Recall that the number of iterations is given by the formula $N_{\text{iterations}}=\frac{\pi}{4}\sqrt{\frac{N}{M}}$, where $N$ is the number of possible states and $M$ is the number of solutions.

### Implement an oracle

Because this is just a demonstration, we're going to solve a trivial task. You're going to give an integer as input to the oracle, and then use the quantum computer to find this integer.

First, you need to implement a marking oracle that takes an integer as input and marks the basis state that corresponds to that integer. You can do this step by using the following operation:

`operation MarkingNumber ( idxMarked : Int, inputQubits : Qubit [], target : Qubit ) : Unit is Adj+Ctl { ControlledOnInt(idxMarked, X)(inputQubits, target); }`

This operation takes as input the integer to be marked and flips the state of the target qubit if the control register state corresponds to the input integer. To do this, it uses the function

`ControledOnInt`

from the Standard library.Because the general operation to run Grover's algorithm that you defined takes a phase oracle as an input, you need to transform your marking oracle into a phase oracle by using the phase kickback trick. We can use the same operation that we used in the module Solve graph coloring problems by using Grover's search:

`operation ApplyMarkingOracleAsPhaseOracle( markingOracle : ((Qubit[], Qubit) => Unit is Adj), register : Qubit[] ) : Unit is Adj { use target = Qubit(); within { X(target); H(target); } apply { markingOracle(register, target); } }`

These two operations combined flip the phase of the basis state that corresponds to the input integer. This step is crucial for each iteration of the Grover's search.

### Calculate the number of iterations

The ideal number of Grover iterations to perform is defined by the number of correct solutions and the total number of possible states. In this case, we have a single correct solution, so we define the function `NIterations`

that takes the number of qubits as input:

```
function NIterations(nQubits : Int) : Int {
let nItems = 1 <<< nQubits;
let angle = ArcSin(1. / Sqrt(IntAsDouble(nItems)));
let nIterations = Round(0.25 * PI() / angle - 0.5);
return nIterations;
}
```

### Create a runnable operation

Now you need to define the main operation that you'll run on Azure Quantum hardware. You need to annotate the operation with the `@EntryPoint`

attribute just before the operation signature. The input parameters of the operation will be provided through the Azure CLI as command-line arguments of the job submission.

Note

For Azure Quantum targets, the output of the main operation needs to have a `Result`

data type, either a single result (`Result`

) or an array of results (`Result[]`

).

The full code should be:

```
namespace MyGroversJob {
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Measurement;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Arithmetic;
open Microsoft.Quantum.Arrays;
@EntryPoint()
operation GroversTest(nQubits : Int, idxMarked : Int) : Result[] {
// Define the oracle
let markingOracle = MarkingNumber(idxMarked, _, _);
let phaseOracle = ApplyMarkingOracleAsPhaseOracle(markingOracle, _);
// Set the number of iterations of the algorithm
let nIterations = NIterations(nQubits);
// Initialize the register to run the algorithm
use qubits = Qubit[nQubits];
// Run the algorithm
RunGroversSearch(qubits, phaseOracle, nIterations);
// Obtain the results and reset the register
return ForEach(MResetZ, qubits);
}
function NIterations(nQubits : Int) : Int {
let nItems = 1 <<< nQubits;
let angle = ArcSin(1. / Sqrt(IntAsDouble(nItems)));
let nIterations = Round(0.25 * PI() / angle - 0.5);
return nIterations;
}
operation MarkingNumber (
idxMarked : Int,
inputQubits : Qubit [],
target : Qubit
) : Unit is Adj+Ctl {
ControlledOnInt(idxMarked, X)(inputQubits, target);
}
operation ApplyMarkingOracleAsPhaseOracle(
markingOracle : ((Qubit[], Qubit) => Unit is Adj),
register : Qubit[]
) : Unit is Adj {
use target = Qubit();
within {
X(target);
H(target);
} apply {
markingOracle(register, target);
}
}
operation RunGroversSearch(register : Qubit[], phaseOracle : ((Qubit[]) => Unit is Adj), iterations : Int) : Unit {
ApplyToEachCA(H, register);
for _ in 1 .. iterations {
phaseOracle(register);
ReflectAboutUniform(register);
}
}
operation ReflectAboutUniform(inputQubits : Qubit[]) : Unit {
within {
ApplyToEachCA(H, inputQubits);
ApplyToEachCA(X, inputQubits);
} apply {
Controlled Z(Most(inputQubits), Tail(inputQubits));
}
}
}
```

## Submit your job to Azure Quantum

Now your code is ready to submit the job to Azure Quantum. First you'll evaluate the resources that your code requires. Then you'll try your code in the IonQ's simulator, and finally you'll run it against hardware.

In this example, we'll set the number of qubits to 2, and the marked integer is going to be 1.

### Estimate the resources for your job

To estimate the resources of the job, the QDK offers you the `ResourcesEstimator`

tool that was presented in the module Explore the key concepts of quantum computing by using Q#.

To use `ResourcesEstimator`

:

Run your program from the command line, and select

`ResourcesEstimator`

as your simulator.`dotnet run -- --n-qubits 2 --idx-marked --simulator ResourcesEstimator`

Review the printed list of the quantum resources that are required to run the job.

`Metric Sum Max CNOT 11 11 QubitClifford 20 20 R 0 0 Measure 2 2 T 7 7 Depth 5 5 Width 3 3 QubitCount 3 3 BorrowedWidth 0 0`

As you can see, this job only requires three qubits, since the `QubitCount`

is 3. Also, we can see that this job uses 11 `CNOT`

gates and 20 `QubitClifford`

gates. This information might be useful to estimate the cost of running the job in different providers.

### Test the code in the simulator

Now that you know what resources you need to run your job, you can test it on the simulator.

Open the Azure CLI, and submit the job by using the following command:

`az quantum job submit --target-id ionq.simulator --job-name MyGroversJob -- --n-qubits 2 --idx-marked 1`

You should obtain something like this example:

`Name Id Status Target Submission time ------------ ------------------------------------ -------- -------- -------------------------------- MyGroversJob yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy Waiting ionq.simulator 2021-01-20T21:34:35.406875+00:00`

To check on the status, use the

`az quantum job show`

command. Make sure to replace the`job-id`

parameter with the`Id`

output by the previous command:`az quantum job show -o table --job-id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy`

Eventually, you'll see the

`Status`

in the preceding table change to`Succeeded`

. After that happens, you can get the results from the job by running`az quantum job output`

:`az quantum job output -o table --job-id yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy`

And the output should be:

`Result Frequency -------- ----------- ------------------------- [1,0] 1.00000000 ▐████████████████████ |`

In this particular case, Grover's algorithm theoretically succeeds with 100 percent probability.

Remember that the integer is represented as its binary notation in little endian (with the least significant bit written first). Binary result 10 is exactly the decimal 1 we used as the input.

### Run your code against hardware

To run your code against hardware, you just need to repeat the same steps as for the simulator but changing the target to `ionq.qpu`

. You can also choose the number of `shots`

to run your program (the default value is 500).

For example, if you choose five shots by using the following command:

```
az quantum job submit --target-id ionq.qpu -- --n-qubits 2 --idx-marked 1 --shots 5
```

You might obtain a result similar to this example:

```
Result Frequency
-------- ----------- -------------------------
[1,0] 0.60000000 ▐████████████ |
[0,1] 0.40000000 ▐███████ |
```

As you can see, the marked integer can't be inferred reliably from the histogram, even though the algorithm theoretically succeeds with a 100 percent of probability. This is because real qubits are subject to noise, and errors can sometimes lead to incorrect computations. To account for these errors, it can be convenient to increase the number of shots to reduce the effect of noise and get a more accurate histogram.

For example, if you choose 1,000 shots, you should obtain something like this example:

```
Result Frequency
-------- ----------- -------------------------
[0,0] 0.07220000 ▐█ |
[1,0] 0.80560000 ▐████████████████ |
[0,1] 0.04500000 ▐█ |
[1,1] 0.07720000 ▐██ |
```

This result is a more accurate statistical representation of the theoretical outcome of the program that enables you to infer the correct result.

In the next unit, you're going to see some ideas to continue exploring quantum computing with Azure Quantum.

Need help? See our troubleshooting guide or provide specific feedback by reporting an issue.