The development kit contains the tools which allow developers to build their own quantum computing programs and experiments. A major component of the Quantum Development Kit preview is the Q# programming language.
According to Microsoft “Q# is a domain-specific programming language used for expressing quantum algorithms. It is to be used for writing sub-programs that execute on an adjunct quantum processor, under the control of a classical host program and computer.”
The Q# programming language is foundational for any developer of quantum software. It is deeply integrated with the Microsoft Visual Studio and hence programming quantum computers is easy for developers who are well-versed with Microsoft Visual Studio.
An interesting feature of Q# is the fact that it supports a basic procedural model (read loops and if/then statements) for writing programs.
The top-level constructs in Q# are user-defined types, operations, and functions.
Q# provides several type models. There are the primitive types such as the Qubit type or the Pauli type. The Qubit type represents a quantum bit or qubit. A quantum computer stores information in the form of qubits as both 1s and 0s at the same time. Qubits can either be tested for identity (equality) or passed to another operation. Actions on Qubits are implemented by calling operations in the Q# standard library.
The Pauli type represents an element of the single-qubit Pauli group. The Pauli group on 1 qubit is the 16-element matrix group consisting of the 2 × 2 identity matrix and all of the Pauli matrices. This type has four possible values: PauliI, PauliX, PauliY, and PauliZ.
There are also array and tuple types for creating new, structured types. It is possible to create arrays of tuples, tuples of arrays, tuples of sub-tuples, etc. Tuple instances are immutable i.e. the contents of a tuple can’t be changed once created.
Q# does not include support for rectangular multi-dimensional arrays.
Q# also has User-defined types. User-defined types may be used anywhere. It is possible to define an array of a user-defined type and to include a user-defined type as an element of a tuple type.
newtype TypeA = (Int, TypeB); newtype TypeB = (Double, TypeC); newtype TypeC = (TypeA, Range); |
A Q# operation is a quantum subroutine, which means it is a callable routine that contains quantum operations.
A Q# function is the traditional subroutine used within a quantum algorithm. It has no quantum operations. You may pass operations or qubits to Functions for processing. However, they can’t allocate or borrow qubits or call operations.
Operations and functions are together known as callables.
A functor in Q# is a factory that specifies a new operation from another operation. An important feature of the function is the fact, that they have access to the implementation of the base operation when defining the implementation of the new operation. This means that functors can perform more complex functions than classical complex functions.
Comments begin with two forward slashes, //, and continue until the end of line. A comment may appear anywhere in a Q# source file, including where statements are not valid. However, end of line comments in the middle of an expression is not supported, although the expression can be multi-lined. Comments can also begin with three forward slashes, ///. Their contents are considered as documentation for the defined callable or user-defined type when they appear immediately before an operation, function, or type definition.
Q# follows the same rules for namespace as other .NET languages. Every Q# operation, function, and user-defined type is defined within a namespace. However, Q# does not support nested namespaces.
The control flow consists of For-Loop, Repeat-Until-Success Loop, Return statement, and the Conditional statement.
Like the traditional for loop, Q# uses the for statement for iteration through an integer range. The statement consists of the keyword for, followed by an identifier, the keyword in, a Range expression, and a statement block.
for (index in 0 .. n-2) { set results[index] = Measure([PauliX], [qubits[index]]); } |
The repeat statement supports the quantum “repeat until success” pattern. It consists of the keyword repeat, followed by a statement block (the loop body), the keyword until, a Boolean expression, the keyword fixup, and another statement block (the fixup).
using ancilla = Qubit[1] { repeat { let anc = ancilla[0]; H(anc); T(anc); CNOT(target,anc); H(anc); let result = M([anc],[PauliZ]); } until result == Zero fixup { (); } } |
Similar to the if-then conditional statement in most programming languages, the if statement in Q# supports conditional execution. It consists of the keyword if, followed by a Boolean expression and a statement block (the then block). This may be followed by any number of else-if clauses, each of which consists of the keyword elif, followed by a Boolean expression and a statement block (the else-if block).
if (result == One) { X(target); } else { Z(target); } |
The return statement ends execution of an operation or function and returns a value to the caller. It consists of the keyword return, followed by an expression of the appropriate type, and a terminating semicolon.
return 1; OR return (); OR return (results, qubits); |
A Q# file consists of one or more namespace declarations. Each namespace declaration contains definitions for user-defined types, operations, and functions.
You can download the Quantum Development Kit here. You can learn more about the features of the Q# language here.