- Hello, welcome to the developer session
on Future-Proofing Your Quantum development with Q# and QIR.
My name is Stefan J. Wernli,
and I'm a senior software developer at Microsoft
on the Azure Quantum Team.
I'm actually pretty new to the team
having only joined in February,
and I've been very excited to dive into contributing
to quantum development
as part of the compiler and runtime team
that works on Q#.
In today's session,
we will be introducing QIR and its design philosophy,
taking a look at the interoperability features it offers,
examining some of examples of using Q# along with QIR,
then a short demo of a quantum algorithm executing via Q#,
and finally wrapping up with some final thoughts
and ways for the community to get involved
in the future of these tools.
That's a lot to cover so let's dive in.
As (indistinct) to the field,
I can't help but notice the kinds of buzzwords
that get associated with quantum computing.
Words like groundbreaking, cutting-edge,
revolutionary, unprecedented,
and these are just a few
that I found on Microsoft blog posts.
These are certainly exciting words
that describe the opportunity to innovate
in the area of quantum computing,
but they also imply some challenges
for those developing in a field
with so much growth and change.
For those of us working on the infrastructure
and application of this new technology,
we must ask them important questions like
what languages and tool sets should we invest in
that we know we can rely on?
How can we take advantage of the classical
and quantum technology that exists now
while leaving room for the new technologies
and innovations that are coming?
And how can we bridge the scenarios and audiences
of today's misc systems
or noisy intermediate scale quantum systems
with the broad usages we anticipate for the future,
or better yet even the future usage we can't anticipate?
At Microsoft,
we certainly been considering these questions
as we develop our stack for Azure Quantum,
and our answer to these is
the Quantum Intermediate Representation or QIR.
So what is this Quantum Intermediate Representation?
QIR is a language and hardware agnostic format
built within the LLVM IR,
meaning it defines how quantum programs
are represented within LLVM.
For those unfamiliar with it
LLVM is a mature open source compiler framework
that (indistinct)
At the IR level,
what we need for quantum is not that different
than the tools that are needed for classical compilation,
leveraging the LLVM tool chain
grants us access to an arsenal of mature tools,
such as those for dependency management and tracking
that we would otherwise need to recreate from scratch.
Additionally,
the LLVM IR has exactly the same purpose
as what we want from QIR.
It serves as a common format
across multiple frontends and backends.
The idea is that each language supports compiling
into that intermediate format
and each execution target is capable of consuming it,
saving the trouble of having to build an end to end compiler
for each combination of language and target.
Many classical languages
already have an LLVM based compiler,
such that building on top of the LLVM tool chain
permits us to integrate with and use libraries or backends
written in these languages.
So we can add domain specific languages
like Microsoft's own Q# to the left side,
and include quantum hardware or simulators on the right.
This opens up great flexibility for mixing and matching
input languages, end users want or need to use
with a variety of potential execution environments.
We are for example, currently collaborating
with Pacific Northwest National Laboratory
to connect to a GPU backend for quantum simulation purposes,
which you can read more about on our recent cloud blog
that discusses this work.
QIR defines how to represent quantum programs
within the LLVM IR without requiring extensions
or modifications of LLVM.
The quantum specific elements
are defined using existing LLVM constructs.
Further, QIR is not specific to Q#.
Any programming language for gate-based Quantum computing
can be compiled into QIR.
Similarly QIR is hardware agnostic,
it does not require a particular quantum instruction
or gate set,
but instead leaves it up to the target environment
to define that,
thus QIR represents the foundation for developing
optimization passes and code transformations
that can be shared across different languages
and back ends while also facilitating integration
between different frameworks.
These optimizations can be existing passes,
supported by LLVM or even new quantum aware passes
that consider the gates and qubits being used.
As an example,
this same cloud blog post at the bottom of the screen
discusses our work with Oak Ridge National Laboratory
to enable integration
with the ex AACC quantum programming framework,
including quantum specific optimizations.
QIR also allows for arbitrary interactions
between classical and quantum computations,
which we believe is a crucial component
of utilizing future quantum systems.
Of course, since that's not yet supported by all backends,
we include support for defining profiles
that identify the subsets of QIR
that corresponds to the capabilities
supported by specific backends.
With all this, you're probably wondering
what does QIR actually look like?
We can start with the example Alan Geller used
in his great blog posts Introducing QIR.
Here we see some Q# code for a simple operation
that establishes a Bell pair between two qubits.
Translating that into QIR,
it's a pretty straightforward representation,
but we see the same two quantum instructions
here prepended with QIS,
to denote them as part of the quantum instruction set,
that the chosen execution target supports.
Again this is normal LLVM code
that we've established a convention
for addressing quantum specific execution.
So this can compile into the existing LLVM toolset.
Of course, this is a very simple example.
So let's take look at something more complex.
Here is an operation used
in a random walk phase estimation sample,
which performs the iterative application of the oracle
in each loop through the random walk.
This example includes some more usage
of Q# language features
like passing an operation as an argument
or using within applied blocks
to automatically perform the adjoint of a preparation.
This code will first perform an H
to prepare the controlQubit,
followed by an Rz and an indication of the oracle,
then unprepare the controlQubit with another H.
The corresponding QIR is definitely more complex,
but it does capture the sequence expressed in Q#,
apologies for it being a little cut off,
but we're gonna focus on specific parts.
You can see that the oracle is passed into the function
as a callable pointer,
and later upgraded to a controlled variant
and invoked using these quantum runtime or RT helpers.
Looking specifically at the quantum instructions,
you can see the stain called H at the top
followed shortly by Rz,
then the preparation for an indication of the oracle,
and finally the last call to H just as we'd expect.
Again because we are using existing LLVM IR syntax,
we're able to take anything from a simple gate sequence
to a more complex algorithm with loops,
conditionals and other classical elements
mixed in with quantum instructions
and represent them in this well supported
open source format.
We can take this even further
with cool things like executing
a Repeat-Until-Success based algorithm
on today's quantum hardware.
Here we see Q# for an algorithm proposed
by our very own Adam Paetznick and Krysta Svore,
in their 2014 paper,
where rotation on a target qubit
is performed using two auxiliary qubits
and repeated execution of gate sequences
until the proper state is measured in the auxiliaries.
Why is this so interesting?
It shows that we can do classical and controlled flow
based on measurement outcomes while qubits remain live,
that is while the quantum state remains coherent.
So how does executing this work?
Let's take a closer look at simulating it in VS code.
I'll go ahead and kick off the simulation on the side here
while I walk through the algorithm.
Here you can see the entry point to the program
where we allocate and prepare the three qubits
in the Pauli-X spaces,
we invoke our recursive Repeat-Until-Success algorithm,
and then perform an Rz on the target qubit
to rotate it back to its initial state.
This means that we expect if the recursive application
has succeeded we'll unprepare that,
so that measurement of the target qubit returns a zero
at the end, indicating a success.
A closer look at that recursive algorithm
that I showed on the slide,
we have the first part of the circuit
that gets applied to the auxiliary and resource qubits,
and then a measurement of the auxiliary qubit
is used as an indicator,
whether or not the correct state has been prepared
in the resource qubit.
If it has, and we measure a zero,
we can continue on with our circuit,
but if not, we unprepare,
and then we can try the algorithm again.
If we do measure the right state,
we move on to the second half of the circuit,
where we use the resource qubit
and the target qubit together
and perform a measurement on the resource qubit.
If we measure a zero,
we know we've succeeded and we can finish there.
But if we measure a one,
then there's a simple correction to return back
to the initial states,
and again we can try the recursive algorithm one more time.
So you can see from the results here on the right
that even performing this algorithm just once,
we have a pretty high probability of success,
but by increasing the allowed number of repetitions,
we're able to get higher and higher probabilities
of success, even with this relatively small sample size,
which shows off the power of this algorithm
and the ability to use mid circuit measurement
to determine whether or not
to repeat the corresponding elements of the algorithm.
This probability begins to approach 100%
as we increase the number of retries
that the circuit is allowed to use.
So graphing that result,
we see again that this probability of success
graphed against the limit on the number of recursions
has a nice curve that matches the expected probabilities
of the algorithm,
but we can take this one step further.
We've actually been able to run this Q# code
against Honeywell's H zero system
using the Azure Quantum service
and see a trend in results that tracks
with a simulated behavior.
This is real data from hardware execution
that demonstrates the power of expressive,
high-level language constructs
to tap into hardware capabilities,
and it's just the beginning.
This is a glimpse of the future that we are building towards
with Azure Quantum.
In Azure Quantum we support execution
of a variety of quantum applications
on a diverse set of backends
from different quantum hardware providers.
And to accomplish this,
we are investing in and incorporating QIR
as the common representation for all of these scenarios.
So to wrap it all up, why use QIR?
Quantum computing as an industry
is still just beginning.
And the quantum computing community is tiny
compared to the broad computing and programming community.
So in order to emulate and accelerate the progression
for quantum computing over the next decade,
not only do we need to take full advantage
of the classical tools and resources at our disposal,
we also need to leverage the insights
into how computing itself has evolved
over the course of more than half a century.
We have the tremendous advantage of hindsight
into what the essential success factors
were (indistinct).
In the coming years,
we expect that there will be exciting advances
in how classical and quantum computations
can interact at the hardware level.
With QIR, we provide a foundation
for developing the software frameworks
that can target today's devices
and the more powerful systems of the future,
that way the investments of today will still pay dividends
as the industry continues to evolve.
And just as importantly, we're getting the word out now,
so that QIR can truly be a community driven effort
built with active collaboration and feedback
from developers all across the industry.
With that in mind,
I highly encourage you to check out the Q# language
repo on GitHub,
where you will find the proposals and design for QIR,
as well as the Q# runtime repo,
which includes an early prototype
demonstrating the usage of QIR with the LLVM
and claim tool chains.
And if you'd like to learn more about Q# specifically,
we have excellent resources in our Q# blog
and the new Q# learning module.
Thank you for your time today,
and I look forward to seeing your contributions to Q#, QIR
and the future of quantum computing.