Skip to content

Working with Jupyter Notebooks

Stefan J. Wernli edited this page Jan 10, 2024 · 8 revisions

The qsharp pip package provides seamless interoperability between Q# and Python. You can execute Q# code right from your Python script or Jupyter notebook.

Sample Notebooks

For an overview of what you can do with Q# and Python, you can browse the sample Jupyter notebooks at pip/samples/sample.ipynb, pip/samples/azure_submission.ipynb and pip/samples/project.ipynb.

Tutorial: Q# in Jupyter Notebooks and VS Code

In this tutorial we will use VS Code, Q#, Python and Jupyter Notebooks to build a quantum random bit generator, simulate it locally, then submit it to Azure Quantum.

  1. Install VS Code and extensions
  2. Create a Jupyter Notebook
  3. Install qsharp
  4. Run Q# in a notebook cell
  5. Use Q# operation results from Python
  6. Run multiple shots of the simulation
  7. Plot simulation results in a histogram
  8. Compile your program using the Base profile
  9. Submit to Azure Quantum

1. Install VS Code and extensions

VS Code can be downloaded at: Visual Studio Code - Code Editing. Redefined

You will also need to install the following extensions for VS Code:

For more information on getting started with Jupyter Notebooks in VS Code, see the documentation at VS Code: Working with Jupyter Notebooks in Visual Studio Code

2. Create a Jupyter Notebook

From the command palette in VS Code, select "Create: New Jupyter Notebook".

image

In the upper right hand corner of the notebook, VS Code will display the version of Python and the virtual Python environment that was selected for the notebook.

image

If VS Code could not find a suitable Python environment, there will be a button instead to select a Jupyter kernel. Click on it and follow the prompts to create or select a Python environment.

3. Install qsharp

It's time to install the Q# package, qsharp.

In your notebook, create a Code cell and type:

%pip install --upgrade qsharp

Click the "play" button to execute the cell. The qsharp pip package will be installed.

image

In the next cell, you can import the package you just installed by running:

import qsharp

image

Now you're ready to add a Q# cell to the notebook to implement your quantum program!

4. Run Q# in a notebook cell

Importing the qsharp module as you did above initializes a Jupyter Notebook cell magic named %%qsharp. This allows you to run Q# code right within a Jupyter cell, interleaved with Python code cells if you like.

Create a new code cell and paste the following code into it:

%%qsharp

// This makes the DumpMachine() function available.
open Microsoft.Quantum.Diagnostics;

operation RandomBit() : Result {
    // Qubits are only accesible for the duration of the scope where they
    // are allocated and are automatically released at the end of the scope.
    use qubit = Qubit();

    // Set the qubit in superposition by applying a Hadamard transformation.
    H(qubit);

    DumpMachine();

    // Measure the qubit. There is a 50% probability of measuring either
    // `Zero` or `One`.
    let result = M(qubit);

    Message($"The result of the measurement is {result}.");

    // Reset the qubit so it can be safely released.
    Reset(qubit);
    return result;
}

// Call the operation we defined above.
RandomBit();

Run the cell by clicking the "play" button or by pressing ctrl+Enter:

image

Here, we created a Q# operation named RandomBit() which allocates a qubit, puts it in a superposition state, measures it, and returns the result. We then called the operation we just defined.

Note a couple of things in the cell output.

Quantum state visualization: The table shown is the output from the DumpMachine() call. It displays the internal state of the simulator, including the measurement probabilities of all the qubits currently allocated.

Message: You can use Message() function to output a string into the cell output.

These two functions are useful for debugging your Q# programs as you develop them.

5. Use Q# operation results from Python

While running Q# in its own notebook cell is a powerful way to develop quantum programs, sometimes you will want to access the results from Q# programs in Python code.

Using qsharp.eval(), you can call any Q# operation that you previously defined in a Q# cell.

Create a new code cell and type:

r = qsharp.eval("RandomBit()")

if r == qsharp.Result.One:
    i = 1
else:
    i = 0

print(f"Python: Got integer {i}!")

image

Note how we switched back to Python here. Calling qsharp.run() runs the Q# expression passed in and converts the result into a Python value. Since the return value is of type Result here, we use the qsharp.Result Python enum to compare the result and convert it to an integer we can use.

6. Run multiple shots of the simulation

To validate that we are in fact generating a random bit, we may want to run the same simulation a number of times, independently. Each independent simulation is called a "shot". Try passing a shots parameter to run() to run your simulation 1000 times:

results = qsharp.run("RandomBit()", shots=1000)

image

Note how the results are aggregated in a Python list. You can now process the results of the Q# simulation using your favorite Python libraries!

7. Plot simulation results in a histogram

Now we can use the result list to generate a histogram using Python's handy matplotlib library. For the next step, we'll need to install the ipympl package so that we can generate interactive widget:

%pip install ipympl

Now, paste the following into a new code cell to generate a histogram:

%matplotlib widget

import matplotlib.pyplot as plt
import numpy as np
from collections import Counter

# Sort the results so that the histogram labels appear in the correct order
results.sort()
# Count the number of times each result appears
counts = Counter(results)

(values, counts) = counts.keys(), counts.values()
xlabels = np.arange(len(counts))
plt.title("RandomBit() Results")
plt.bar(xlabels, counts)
plt.xticks(xlabels, values)
plt.show()

image

Just as we would expect, the number of occurrences of One and Zero are about equal.

9. Compile your program using the Base profile

We can now run our program on real quantum hardware or simulators hosted on Azure Quantum.

Unlike the local quantum simulator, Azure Quantum backends do not yet support the full capabilities required to run any Q# programs. In order to compile and submit Q# programs to Azure Quantum, we need to set our target profile to tell Q# which capabilities that our target hardware supports.

In a new Python code cell, reinitialize the Q# interpreter with the base profile:

qsharp.init(target_profile=qsharp.TargetProfile.Base)

This reconfigures the Q# interpreter so that only operations included in the Base target profile are permitted in our program.

In the next code cell, let's redefine our random number generator operation to get ready to compile and submit it to Azure Quantum.

%%qsharp

operation Random() : Result {
    use q = Qubit();
    H(q);
    let result = M(q);
    Reset(q);
    return result
}

operation RandomNBits(N: Int): Result[] {
    mutable results = [];
    for i in 0 .. N - 1 {
        let r = Random();
        set results += [r];
    }
    return results
}

8. Submit to Azure Quantum

For this part, you'll need the azure-quantum package. Install it using pip:

%pip install azure-quantum

You will also need an Azure Quantum workspace set up if you don't already have one. For instructions on how to create a workspace, see the documentation at: Create an Azure Quantum workspace

In your notebook, run a code cell initializing the following variables for your own workspace:

subscription_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
resource_group = 'myresourcegroup'
workspace_name = 'myworkspace'
location = 'mylocation'

Now, connect to Azure Quantum and submit your Q# program:

import azure.quantum

operation = qsharp.compile("RandomNBits(4)")

workspace = azure.quantum.Workspace(
    subscription_id=subscription_id,
    resource_group=resource_group,
    name=workspace_name,
    location=location,
)
target = workspace.get_targets("rigetti.sim.qvm")
job = target.submit(operation, "my-azure-quantum-job", input_params={ "count": 100 })
job.get_results()

Running this cell may cause a browser window to open up, or display instructions on how to sign in to Azure Quantum in the cell output. Follow the instructions for signing in to allow the script to continue.

Let's take a closer look at the call to Q# above:

operation = qsharp.compile("RandomNBits(4)")

The string "RandomNBits(4)" is called an entry expression, and it's exactly what it reads like: a call into the RandomNBits function with 4 as the argument. This expression is treated as the entry point to the program submitted to Azure Quantum. You can pass any valid Q# expression as the entry expression.

Once the job is done executing on Azure Quantum, the results will be shown in the cell output:

image

You can now generate a histogram from these results just like we did above with the local simulation, or post-process the results using any Python library of your choosing.

Using other editors

This tutorial showed you how to use Q# and Python in our favorite editor, VS Code. If you are an experienced Python developer, you may want to use Q# with your notebook editor of choice, such as JupyterLab. This is certainly possible, as qsharp-lang is a pip package without any dependencies that can be invoked from any Python environment.

If you do use JupyterLab, don't forget to install qsharp-jupyterlab, our JupyterLab extension that provides syntax highlighting in Q# cells:

pip install qsharp-jupyterlab

If you prefer not to use Jupyter notebooks, qsharp-lang works well in Python scripts as well.

Further documentation

Now that you've gotten started with Q# and Python, explore the Q# playground (microsoft.github.io) for more Q# samples and tutorials. All of the code samples found on the playground are runnable in Jupyter notebooks as well.