A few years ago, researchers were making headlines with their advancements in the field of quantum computing. IBM made a computer with support for 50-qubit processing and not long after that, Google unveiled their own, with support for 72-qubits. Now there are even chips with quantum processing power that are similar in size to traditional processors. Looking forward, it seems that tech companies are hoping to make sure that when the big push towards quantum computing is here, that programmers will be able to adapt.

IBM has its own cloud-based servers that allow users to submit requests to use quantum resources for their own projects. Google has an online simulator to experiment with qubits first-hand. One of the most interesting releases is Microsoft's Q# language, a framework that integrates traditional C# programs with a quantum simulator that manipulates qubits using Q# code.

So what's the big deal?
Quantum computing is not exactly afforadable right now. Quantum computers can cost upwards of $15 million, and at 72 qubits, they have significantly less data units than traditional computers which can utilize 2^64 shannon-bits. The trick is that quantum bits are held in coherent superposition which allows them to hold data amounting to two shannon-bits at a time. Early on this simple difference led to a phenomenon called quantum advantage, or quantum speedup, the ability to solve a given problem much faster than a traditional computer. For example, in 1994, Peter Shor formulated a quantum algorithm that can factorize an integer in polynomial time. Recently there has been a race to reach quantum supremacy, meaning the discovery of quantum alogorithms that traditional computing has failed to implement practically. With the release of Google's 72-qubit computer, they have argued that they are close to achieving this level of quantum performance. Once quantum computing reaches maturity, there's no telling what kind of problems they will be able to solve.

Getting Started
Though no one keeps their house cold enough to be able to run a quantum computer, it is possible to at least simulate one. Microsoft's Q# framework makes it pretty simple; you can read the documentation here.

To get started, all you have to do is install .NET Core, open a terminal, and run:
dotnet tool install -g Microsoft.Quantum.IQSharp'.
Running a quantum algorithm is as simple as opening Visual Studio and creating a C# driver script. From the Microsoft example[1],

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())

Running the driver will run the HelloQ operation from the .qs script in the project. It will look for the operation in the Q# file that matches the same namespace:

namespace Quantum.Bell
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Primitive;

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

The syntax of the script itself is very similar to both C# and F#[2]:

  • Each Q# script must declare a namespace.
  • Statements are terminated using ; and elements of sequences are separated using ,.
  • Types are referenced using : with the reference name coming before the type.
  • Range expressions are defined using .. and are inclusive. For example, for(i in 1..3) is equivalent to for i in range(1, 4) in Python.
  • Variables are defined using the let keyword.
  • Variables are immutable by default. In order to allow them to be modified, they must be declared using mutable instead of let.

Q# is a strongly typed language. It supplies the following primitive types:[3]

  • Int, BigInt, Double, String, Range.
  • Bool, with a valid value of true or false.
  • Qubit which represents a quantum bit. They can only be manipulated using the standard library. For example M(q) would measure a qubit q.
  • The Pauli type represents the four Pauli operators and is an enumeration containing {PauliI, PauliX, PauliY, PauliZ}.
  • The Result type is the result of using the M operator. It can either be Result.One or Result.Zero.
  • Unit, which represents a function that returns no information. Its only possible value is ().

Any type T1 can be represented in an array: 'T1[]. 'T1[][] represents a jagged array, meaning that the array sizes are not fixed in any way.
Tuples are also supported, allowing any combination of types. These types may be deconstructed similarly to Python like so: let (a, (b, c)) = (7, (4, 5));. Singletons are translated into their enclosing type, e.g. (5) == 5.[3:1]

Q# supports the following control flow operations:

  • using works similarly to its usage in C#. Qubits must be allocated using this keyword. For example, using(qubit = Qubit()) { ... }
  • borrowing is similar to using. It is used to "borrow" already allocated qubits and promises to leave them in their previous state once the block has executed.
  • for, using a Python-style in keyword. The left side can be a variable or a tuple deconstruction, and the right side can be a Range or an array type
  • repeat. It has three parts that are all required: a repeat code block, an until statement that evaluates a boolean, and a fixup code block. If no fixup code is required, it may be an empty tuple ().
  • C-style if, elif, and else.
  • return to return a call from a callable.
  • fail, which is used to terminate execution and send an error message to the classical driver. For example, fail $"{var} was invalid.";

There are two types of callables in Q#[3:2].

  • Operations are defined using the operation keyword and define routines that use quantum operations.
  • Functions are classical subroutines that do not use quantum operators, or allocate or borrow qubits, but are allowed to take a qubit as an input.
    Callables take a single value as an input and return a single output: ('Tinput => 'Tresult) (operation) or ('Tinput -> 'Tresult) (function).

Functors are factories that can be applied to operations to generate a new derivative operation[3:3]. There are two standard types of functors.
The Adjoint functor takes the complex conjugate transpose of an operation. Usually, this is the inverse. For example, running Adjoint QFT() returns the inverse quantum fourier transform of the input.
The Controlled functor conditionally applies the base operation if and only if all the input's control bits are in the state |1⟩. If they are in a superposition, the base operation is applied only to the appropriate part of the superposition, making it useful for generating entanglement.

Below is an example I've written. It implements the Shor algorithm for factoring numbers into coprimes.

  1. "Write a quantum program", Microsoft Docs, 2019. [Online]. Available: https://docs.microsoft.com. [Accessed: 06- Apr- 2019]. ↩︎

  2. "Expressions", Microsoft Docs, 2019. [Online]. Available: https://docs.microsoft.com. [Accesed: 06- Apr- 2019]. ↩︎

  3. "Q# Type Model", Microsoft Docs, 2019. [Online]. Available: https://docs.microsoft.com. [Accessed: 06- Apr- 2019]. ↩︎ ↩︎ ↩︎ ↩︎