Embedding Q# in your favorite languages and platforms

Cassandra Granade

It’s no secret that Q# and the Quantum Development Kit make it easy for you to write quantum programs and run them on simulators, on hardware via the Azure Quantum service, from Python, from .NET, or even from a Jupyter notebook. More than that, though, the infrastructure that powers all of these different ways of using Q# also allows for building new and exciting ways of writing and running quantum programs. In this post, we’ll dig down into that infrastructure a bit, and how you can use that infrastructure to connect Q# to your favorite languages and platforms.

Python and Interactive Q#

To kick things off, let’s take a look at how Q# connects out to platforms like Python and Jupyter. Both platforms are centered heavily around interactive usage, where programs aren’t necessarily precompiled, but are built up by developers one piece at a time.

Graphical user interface, text, application, email Description automatically generated

On its own, this is very different from how one might use Q# from the command line, or when building a .NET application that uses quantum computing. To make Q# work in an interactive environment, the Quantum Development Kit also includes IQ#, short for Interactive Q# and following the naming scheme popularized by IPython, IJulia, and other such tools. The IQ# kernel uses the Q# compiler and runtime as a library, allowing it to call into the Q# compiler and runtime on-the-fly. This is the same approach used by many other tools included in the Quantum Development Kit, such as the Q# compiler’s command-line interface (qsc.exe), or the language server used by the Visual Studio Code and Visual Studio 2019 extensions.

Graphical user interface, application Description automatically generated

Using the IQ# kernel from a Q# notebook

As the IQ# kernel gets messages from Jupyter clients, it passes along Q# source code to the compiler, getting back programs that can be run on simulators or submitted to Azure Quantum services. This approach lets us connect interactive environments like Jupyter to the rest of the Quantum Development Kit. From the perspective of the Jupyter platform, the IQ# kernel is just another executable; that the IQ# kernel is written using .NET is an implementation detail at that point.

The same approach also allows for using Python as a host language for your quantum programs. In particular, the jupyter_client package can be used to call from a Python host program into any kernel recognized by the Jupyter platform. The qsharp package for Python uses jupyter_client to load IQ#, send commands to the kernel, and get rich display data back. Behind the scenes, your Python host program acts like another Jupyter client, exchanging messages with the IQ# kernel to let you build up your Q# program from a scripted environment.

Graphical user interface, application Description automatically generated

Using the IQ# kernel from a Python program

Calling Quantum Programs from Julia? Lua…? PowerShell…‽

IQ# isn’t just an executable program, however. Most of the logic that IQ# uses to interact with the Q# compiler and runtime is packaged as its own library, available on NuGet.org as the Microsoft.Quantum.IQSharp.Core and Microsoft.Quantum.IQSharp.Jupyter packages. These two packages can be used by any other .NET applications to implement your own language integrations for Q#.

For example, we can write a small C# application that uses the IQ# library to expose the Q# compiler and runtime through a series of plain JSON messages that are easy to send and receive from other languages. Using JSON.jl, we can write a client for this new application in Julia, and use it to interactively build quantum applications from a Julia environment.

Graphical user interface, text, application Description automatically generated

Calling into Q# from Julia

This approach isn’t just limited to Julia, but can be used most places where you can call into command-line applications. The same C# application that we used above can also be quickly adapted to let us call into Q# from other languages like Lua, or even PowerShell.

Graphical user interface, text, application Description automatically generated

Calling into Q# from Lua

Graphical user interface, text, application Description automatically generated

Calling into Q# from PowerShell

Check out the code sample at https://github.com/cgranade/qsharp-server!

Writing Bots with Dependency Injection

We can go even further, though, and use IQ# as a library to embed Q# in web applications and chat bots. The different components that make up IQ# are exposed by the Microsoft.Quantum.IQSharp.Core and Microsoft.Quantum.IQSharp.Jupyter packages as services that can be added to your own applications using ASP.NET Core Dependency Injection.

To see how this works, let’s look at what it takes to add IQ# to a Discord bot:

public void ConfigureServices(IServiceCollection services)
{
     services
     // Add services needed for acting as a Discord application.
        .AddDiscord()
            // Add logging services.
            .AddLogging(
                builder => builder
                    .SetMinimumLevel(LogLevel.Debug)
                    .AddAzureWebAppDiagnostics()
                    .AddConsole()
                )
        // Add services unique to this bot.
        .AddSingleton<CommandHandler>()
        .AddSingleton<Bot>();

    // Add services needed for working with the Q# compiler and runtime.
    services.AddIQSharp();

    // Add services needed for the bot health web app.
    services.AddRazorPages();
    services.AddServerSideBlazor();
}

Here, AddIQSharp is an extension method provided by the IQ# library that adds IQ# services to an existing service collection. Since Discord.NET is written using the same dependency injection framework, calling into AddIQSharp lets us immediately ask for IQ# services the same way we would services made available by Discord.NET:

public class SimulateModule : ModuleBase<SocketCommandContext>
{
    private readonly ISnippets snippets;
    private readonly IWorkspace workspace;
    private readonly ILogger logger;
    private static readonly Emoji waiting = new Emoji("⌛");

    public SimulateModule(
        ISnippets snippets, IWorkspace workspace,
        ILogger<SimulateModule> logger)
    {
        this.snippets = snippets;
        this.workspace = workspace;
        this.logger = logger;
    }

    // ...

Here, our bot’s %simulate command uses its constructor to ask for IQ# services like its snippets and workspace managers, as well as an ASP.NET Core logger used to provide debugging information.

The same approach can even be used to expose a REST API for the Q# compiler and runtime! For example, the Web project in the microsoft/iqsharp repository uses IQ# together with ASP.NET Core to allow using Q# over HTTP.

 

Wrap-up

Whatever tools and platforms you love, Q# and the Quantum Development Kit are there to help you make the most out of quantum computing. Using tools like the IQ# library and kernel, you can easily extend Q# to work with a wide range of languages, platforms, and ecosystems. Give it a try, and let us know what you build!

Posted in Q#

0 comments

Discussion is closed.

Feedback usabilla icon