Challenging myself with Microsoft's Quantum Computing development tools and Q#

Challenging myself with Microsoft's Quantum Computing development tools and Q#

Every evening I read a book to my youngest son. He’s turning 2 later this year and loves books. Or perhaps it’s just his way of buying more time before going to sleep.

We started with Astrophysics for Babies, back in 2018. Since then, we’ve read Newtonian Physics for Babies, Rocket Science for Babies, General Relativity for Babies and plenty more. One of his favorites is Quantum Computing for Babies:

It’s pretty great! Taking a complex topic, simplifying it as much as possible and still keeping it funny and approachable is a huge accomplishment from the authors.

Don’t worry, we read normal children’s books, too.

Last night, after putting my son to bed, I started thinking. Where, exactly, are we in trying out Quantum Computing ourselves? I remember from last year a few announcements during Microsoft’s keynotes, that there is something I can try out on my own. After all, how challenging can it be?

Turns out, very.

I’m not a theoretical physicist. I’m even bad at maths. But what I’m good at is trying out things. And I’m not afraid to fail.

Developing using Quantum Computing

In late 2017, the Q# programming was announced. In May 2019, it was open-sourced and you can find it on GitHub.

Q# is a bit like C#, but it’s still very different. I can’t say I’ve mastered Q#, but I did spend a few hours reading about the differences so at least I can comfortably say I’m at a pre-sales level of knowledge now! The usual conventions are the same — statements end in a semicolon (;), types are introduced with a colon (:) and commas (,) are used to separate elements in a sequence.

Primitive types, such as Int, BigInt, and Bool are there also. Then there’s the Qubit type representing a quantum bit, that you test with a quantum processor. I lack one, so I’m using the simulator.

You can run your Q# code in multiple ways. The easiest is in Visual Studio using a mix of Q# and C# project, where Q# is the logic, and C# is the driver for calling that logic. You can also use Jupyter Notebooks, which allows for running Q# code in a browser. The third option is to use the Quantum Development Kit in Python.

The idea with Q#, to my understanding, is to be able to write code that runs on multiple different quantum computing platforms. The language has crucial features built-in, such as error correction.

Quantum Computing – Explain Like I’m 5

I’ve semi-actively entertained myself reading about quantum computing in recent years. It’s nothing new, as Richard Feynman and Yuri Manin proposed the idea for quantum computers in the 1980s. If my parents were to ask me, what quantum computing is, and they might be as impatient as myself at times, I’d try to explain as follows:

Simulating many interacting particles, such as neutrons, requires a lot of computing powers. Typical conventional computers do not have such computing powers, and we need something more powerful. These advanced computers would need to track each possible configuration, not just the 1s and 0s like in a traditional computer.

Wikipedia puts this more neatly:

Quantum computing is the use of quantum-mechanical phenomena such as superposition and entanglement to perform computation. A quantum computer is used to perform such computation, which can be implemented theoretically or physicallyWikipedia on Quantum Computing ( https://en.wikipedia.org/wiki/Quantum_computing)

This introduces two new things we need to understand a bit better. Superposition and entanglement.

Superposition means that we can have any two (or more) quantum states added together. This has something to do with a Schrödinger equation, but I felt it’s beyond the scope of me trying to do a Hello World in a quantum computer. Qubit logical states can be written out as |0> and |1>. These result in a 0 and a 1 when converted to classical logic. This is highly simplified and lacking a lot of details, of course. You can read the full theory on Wikipedia, if you’re interested.

Entanglement, is as the name suggests, a phenomenon where pairs or groups of particles are entangled, even with a considerable distance. Individual particles are not separate, but inseparable as a whole. I’m not sure why I need this information, but reading through the theory on Wikipedia, it was entertaining nonetheless.

I understood from Microsoft’s introduction to quantum computing that familiarity with vectors and matrices, advanced matrix concepts and Pauli measurements would be helpful also. You can check the explanations here. Still, I just want to do a Hello World and then figure how much more I need to study.

Time to get coding!

Writing my first Q# program

To prepare my environment, I installed the Q# Visual Studio Extension. This adds three new project templates for me:

I chose Q# application, which then shows me a project with two project files – the .qs file for Q#, and the .cs file for Driver. I need to write my algorithm in Q#, and then call that algorithm logic from my driver using C#.

The Hello World-equivalent to Q# is as follows:

namespace Quantum.Bell {
    open Microsoft.Quantum.Intrinsic;
    open Microsoft.Quantum.Canon;

    operation HelloQ () : Unit {
        Message("Hello quantum world!");
    }
}

And the C# driver logic is the following:

using System;

using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;

namespace Quantum.Bell
{
    class Driver
    {
        static void Main(string[] args)
        {
            using (var qsim = new QuantumSimulator())
            {
                HelloQ.Run(qsim).Wait();
            }
        }
    }
}

C# is a familiar one. Q# looks a bit odd but still digestible. For now.

I followed a few tutorials on docs.microsoft.com to try to build something useful. I ended up with a mutilated operation, that uses four qubits. These are set to |0> and |1> alternatively, and then in my C# I run 5000 estimations against these qubits and measure the results together with estimates on how much resources I’d need for my code.

Here’s the Q# portion:

operation BellTest (count : Int, initial: Result) : (Int, Int, Int) {
mutable numOnes = 0;
mutable agree = 0;
using ((q0, q1, q2, q3) = (Qubit(), Qubit(), Qubit(), Qubit())) {
	for (test in 1..count)
	{
		Set (initial, q0);
		Set (Zero, q1);
		Set (initial, q2);
		Set (Zero, q3);

		H(q0);
		H(q1);
		H(q2);
		H(q3);
		
		CNOT(q0,q1);
		CNOT(q2,q3);
		let res = M (q0);
		let res2 = M (q2);

		if (M (q1) == res) {
			set agree += 1;
		}

		if (M (q3) == res2) {
			set agree += 1;
		}

		// Count the number of ones we saw:
		if (res == One) {
			set numOnes += 1;
		}

		if (res2 == One) {
			set numOnes += 1;
		}
		
	}
	
	Set(Zero, q0);
	Set(Zero, q1);
	Set(Zero, q2);
	Set(Zero, q3);

}

// Return number of times we saw a |0> and number of times we saw a |1>
return (count-numOnes, numOnes, agree);
}

I start by allocating four qubits. I then run a for-loop as many times as I define in my driver (C#) code). The logic then happens inside the loop.

First, I set each qubit to a state – qubit 1 and qubit 3 are set in zero (|0>), and qubit 0 and qubit 2 are set in the initial state, which is the initial value of the given qubit.

Then, using something called a Hadamard gate (the H() operation) I’m flipping all qubits halfway. As opposed to just flipping them from 0 to 1, or 1 to 0, I’m flipping them a little bit.

Then, using the CNOT() operation, which stands for a Pauli X Gate, I’m entangling two qubits together. It’s like a NOT gate. Therefore, qubit 0 and 1 become entangled, and qubit 2 and qubit 3 become entangled.

Finally, I’m measuring the qubits using the M() operation, which performs a measurement on a single qubit using the Pauli Z basis. This measures the qubit’s value.

The C# driver, that calls this code, looks like this:

static void Main(string[] args)
{
	var estimator = new ResourcesEstimator();
	BellTest.Run(estimator, 5000, Result.Zero).Wait();

	System.Console.WriteLine(estimator.ToTSV());
}

Running the C# code, I get the following metrics:

Metric          Sum
CNOT            10000
QubitClifford   20000
R               0
Measure         40004
T               0
Depth           0
Width           4
BorrowedWidth   0

CNOT is a Controlled Pauli X Gate, and I executed 10,000 of those. QubitClifford is the count of any single-qubit Clifford and Pauli gates executed. Width is the maximum number of qubits allocated during the measurement execution.

Interesting.. but, why?

I’m pleased that I can run such complex computing concepts on my workstation at home. I’ve barely scratched the surface of quantum computing and Q# with my slightly modified Hello World sample. It’s exciting, yet at the same time, you’re constantly flooded with information and theories that are impossible to comprehend without sufficient background in physics and maths.

Many people consider doing AI today. They might use Azure’s Cognitive Services, simply by calling a REST API and working with the data that is received. Yet, not many people actually claim to understand the underlying theory and abstraction layers of the services. The same, although at a much higher proportion, applies to Q# today. It’s relatively easy to type out code in Q#, yet once you get to the actual operations such as the quantum algorithms like Quantum Fourier Transform and Beauregard Adder, I’m not sure many IT Pros or developers actually have an inkling of a clue what’s happening. And that’s fine.

As someone once said, “we keep reading our books, you keep coloring them” — I’m happy to use the colored pencils Q# gives me, without needing to understanding how those pencils came to be.

Perhaps Quantum Computing is not on the verge of becoming a mainstream development platform. The quality of the tools, the attention to detail within the documentation and the privilege of being able to “just run it”, is beyond my expectations.

It will be interesting to follow Q# and Microsoft’s future in Quantum Computing to see where we’re headed.