Q Sharp
This article may rely excessively on sources too closely associated with the subject, potentially preventing the article from being verifiable and neutral. (September 2018) |
Paradigm | Quantum, functional, imperative |
---|---|
Designed by | Microsoft Research (quantum architectures and computation group; QuArC) |
Developer | Microsoft |
First appeared | December 11, 2017 |
Typing discipline | Static, strong |
Platform | Common Language Infrastructure |
License | MIT License[1] |
Filename extensions | .qs |
Website | docs |
Influenced by | |
C#, F#, Python |
Q# (pronounced as Q sharp) is a domain-specific programming language used for expressing quantum algorithms.[2] It was initially released to the public by Microsoft as part of the Quantum Development Kit.[3]
History
Historically, Microsoft Research had two teams interested in quantum computing, the QuArC team based in Redmond,[4] directed by Krysta Svore, that explored the construction of quantum circuitry, and Station Q initially located in Santa Barbara and directed by Michael Freedman, that explored topological quantum computing.[5][6]
During a Microsoft Ignite Keynote on September 26, 2017, Microsoft announced that they were going to release a new programming language geared specifically towards quantum computers.[7] On December 11, 2017, Microsoft released Q# as a part of the Quantum Development Kit.[3]
At Build 2019, Microsoft announced that it is open-sourcing the Quantum Development Kit, including its Q# compilers and simulators.[8]
Bettina Heim currently leads the Q# language development effort.[9][10]
Usage
Q# is available as a separately downloaded extension for Visual Studio,[11] but it can also be run as an independent tool from the Command line or Visual Studio Code. The Quantum Development Kit ships with a quantum simulator which is capable of running Q#.[12]
In order to invoke the quantum simulator, another .NET programming language, usually C#, is used, which provides the (classical) input data for the simulator and reads the (classical) output data from the simulator.[13]
Features
A primary feature of Q# is the ability to create and use qubits for algorithms. As a consequence, some of the most prominent features of Q# are the ability to entangle and introduce superpositioning to qubits via Controlled NOT gates and Hadamard gates, respectively, as well as Toffoli Gates, Pauli X, Y, Z Gate, and many more which are used for a variety of operations; see the list at the article on quantum logic gates.[14]
The hardware stack that will eventually come together with Q# is expected to implement Qubits as topological qubits. The quantum simulator that is shipped with the Quantum Development Kit today is capable of processing up to 32 qubits on a user machine and up to 40 qubits on Azure.[15]
Documentation and resources
Currently, the resources available for Q# are scarce, but the official documentation is published: Microsoft Developer Network: Q#. Microsoft Quantum Github repository is also a large collection of sample programs implementing a variety of Quantum algorithms and their tests.
Microsoft has also hosted a Quantum Coding contest on Codeforces here: Microsoft Q# Coding Contest - Codeforces, and also provided related material to help answer the questions in the blog posts, plus the detailed solutions in the tutorials.
Microsoft hosts a set of learning exercises to help learn Q# on GitHub: microsoft/QuantumKatas with links to resources, and answers to the problems.
Syntax
Q# is syntactically related to both C# and F# yet also has some significant differences.
Similarities with C#
- Uses
namespace
for code isolation - All statements end with a
;
- Curly braces are used for statements of scope
- Single line comments are done using
//
- Variable data types such as
Int
Double
String
andBool
are similar, although capitalised (and Int is 64-bit)[16] - Qubits are allocated and disposed inside a
using
block. - Lambda functions using the
=>
operator. - Results are returned using the
return
keyword.
Similarities with F#
- Variables are declared using either
let
ormutable
[2] - First-order functions
- Modules, which are imported using the
open
keyword - The datatype is declared after the variable name
- The range operator
..
for … in
loops- Every operation/function has a return value, rather than
void
. Instead ofvoid
, an empty Tuple()
is returned. - Definition of record datatypes (using the
newtype
keyword, instead oftype
).
Differences
- Functions are declared using the
function
keyword - Operations on the quantum computer are declared using the
operation
keyword - Lack of multiline comments
- Asserts instead of throwing exceptions
- Documentation is written in Markdown instead of XML-based documentation tags
Example
The following source code is a multiplexer from the official Microsoft Q# library repository.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Arithmetic;
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Math;
/// # Summary
/// Applies a multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by n-qubit number state $\ket{j}$.
///
/// $U = \sum^{N-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () is Adj + Ctl))`
/// is a function that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// ## index
/// $n$-qubit control register that encodes number states $\ket{j}$ in
/// little-endian format.
///
/// ## target
/// Generic qubit register that $V_j$ acts on.
///
/// # Remarks
/// `coefficients` will be padded with identity elements if
/// fewer than $2^n$ are specified. This implementation uses
/// $n-1$ auxiliary qubits.
///
/// # References
/// - [ *Andrew M. Childs, Dmitri Maslov, Yunseong Nam, Neil J. Ross, Yuan Su*,
/// arXiv:1711.10980](https://arxiv.org/abs/1711.10980)
operation MultiplexOperationsFromGenerator<'T>(unitaryGenerator : (Int, (Int -> ('T => Unit is Adj + Ctl))), index: LittleEndian, target: 'T) : Unit is Ctl + Adj {
let (nUnitaries, unitaryFunction) = unitaryGenerator;
let unitaryGeneratorWithOffset = (nUnitaries, 0, unitaryFunction);
if Length(index!) == 0 {
fail "MultiplexOperations failed. Number of index qubits must be greater than 0.";
}
if nUnitaries > 0 {
let auxiliary = [];
Adjoint MultiplexOperationsFromGeneratorImpl(unitaryGeneratorWithOffset, auxiliary, index, target);
}
}
/// # Summary
/// Implementation step of `MultiplexOperationsFromGenerator`.
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexOperationsFromGenerator
internal operation MultiplexOperationsFromGeneratorImpl<'T>(unitaryGenerator : (Int, Int, (Int -> ('T => Unit is Adj + Ctl))), auxiliary: Qubit[], index: LittleEndian, target: 'T)
: Unit {
body (...) {
let nIndex = Length(index!);
let nStates = 2^nIndex;
let (nUnitaries, unitaryOffset, unitaryFunction) = unitaryGenerator;
let nUnitariesLeft = MinI(nUnitaries, nStates / 2);
let nUnitariesRight = MinI(nUnitaries, nStates);
let leftUnitaries = (nUnitariesLeft, unitaryOffset, unitaryFunction);
let rightUnitaries = (nUnitariesRight - nUnitariesLeft, unitaryOffset + nUnitariesLeft, unitaryFunction);
let newControls = LittleEndian(Most(index!));
if nUnitaries > 0 {
if Length(auxiliary) == 1 and nIndex == 0 {
// Termination case
(Controlled Adjoint (unitaryFunction(unitaryOffset)))(auxiliary, target);
} elif Length(auxiliary) == 0 and nIndex >= 1 {
// Start case
let newauxiliary = Tail(index!);
if nUnitariesRight > 0 {
MultiplexOperationsFromGeneratorImpl(rightUnitaries, [newauxiliary], newControls, target);
}
within {
X(newauxiliary);
} apply {
MultiplexOperationsFromGeneratorImpl(leftUnitaries, [newauxiliary], newControls, target);
}
} else {
// Recursion that reduces nIndex by 1 and sets Length(auxiliary) to 1.
let controls = [Tail(index!)] + auxiliary;
use newauxiliary = Qubit();
use andauxiliary = Qubit[MaxI(0, Length(controls) - 2)];
within {
ApplyAndChain(andauxiliary, controls, newauxiliary);
} apply {
if nUnitariesRight > 0 {
MultiplexOperationsFromGeneratorImpl(rightUnitaries, [newauxiliary], newControls, target);
}
within {
(Controlled X)(auxiliary, newauxiliary);
} apply {
MultiplexOperationsFromGeneratorImpl(leftUnitaries, [newauxiliary], newControls, target);
}
}
}
}
}
adjoint auto;
controlled (controlRegister, ...) {
MultiplexOperationsFromGeneratorImpl(unitaryGenerator, auxiliary + controlRegister, index, target);
}
adjoint controlled auto;
}
/// # Summary
/// Applies multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by n-qubit number state $\ket{j}$.
///
/// $U = \sum^{N-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () is Adj + Ctl))`
/// is a function that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// ## index
/// $n$-qubit control register that encodes number states $\ket{j}$ in
/// little-endian format.
///
/// ## target
/// Generic qubit register that $V_j$ acts on.
///
/// # Remarks
/// `coefficients` will be padded with identity elements if
/// fewer than $2^n$ are specified. This version is implemented
/// directly by looping through n-controlled unitary operators.
operation MultiplexOperationsBruteForceFromGenerator<'T>(unitaryGenerator : (Int, (Int -> ('T => Unit is Adj + Ctl))), index: LittleEndian, target: 'T)
: Unit is Adj + Ctl {
let nIndex = Length(index!);
let nStates = 2^nIndex;
let (nUnitaries, unitaryFunction) = unitaryGenerator;
for idxOp in 0..MinI(nStates,nUnitaries) - 1 {
(ControlledOnInt(idxOp, unitaryFunction(idxOp)))(index!, target);
}
}
/// # Summary
/// Returns a multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by n-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () is Adj + Ctl))`
/// is a function that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// # Output
/// A multiply-controlled unitary operation $U$ that applies unitaries
/// described by `unitaryGenerator`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexOperationsFromGenerator
function MultiplexerFromGenerator(unitaryGenerator : (Int, (Int -> (Qubit[] => Unit is Adj + Ctl)))) : ((LittleEndian, Qubit[]) => Unit is Adj + Ctl) {
return MultiplexOperationsFromGenerator(unitaryGenerator, _, _);
}
/// # Summary
/// Returns a multiply-controlled unitary operation $U$ that applies a
/// unitary $V_j$ when controlled by n-qubit number state $\ket{j}$.
///
/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
///
/// # Input
/// ## unitaryGenerator
/// A tuple where the first element `Int` is the number of unitaries $N$,
/// and the second element `(Int -> ('T => () is Adj + Ctl))`
/// is a function that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
/// operation $V_j$.
///
/// # Output
/// A multiply-controlled unitary operation $U$ that applies unitaries
/// described by `unitaryGenerator`.
///
/// # See Also
/// - Microsoft.Quantum.Canon.MultiplexOperationsBruteForceFromGenerator
function MultiplexerBruteForceFromGenerator(unitaryGenerator : (Int, (Int -> (Qubit[] => Unit is Adj + Ctl)))) : ((LittleEndian, Qubit[]) => Unit is Adj + Ctl) {
return MultiplexOperationsBruteForceFromGenerator(unitaryGenerator, _, _);
}
/// # Summary
/// Computes a chain of AND gates
///
/// # Description
/// The auxiliary qubits to compute temporary results must be specified explicitly.
/// The length of that register is `Length(ctrlRegister) - 2`, if there are at least
/// two controls, otherwise the length is 0.
internal operation ApplyAndChain(auxRegister : Qubit[], ctrlRegister : Qubit[], target : Qubit)
: Unit is Adj {
if Length(ctrlRegister) == 0 {
X(target);
} elif Length(ctrlRegister) == 1 {
CNOT(Head(ctrlRegister), target);
} else {
EqualityFactI(Length(auxRegister), Length(ctrlRegister) - 2, "Unexpected number of auxiliary qubits");
let controls1 = ctrlRegister[0..0] + auxRegister;
let controls2 = Rest(ctrlRegister);
let targets = auxRegister + [target];
ApplyToEachA(ApplyAnd, Zipped3(controls1, controls2, targets));
}
}
}
References
- ^ "Introduction to Q#" (PDF). University of Washington.
- ^ a b QuantumWriter. "The Q# Programming Language". docs.microsoft.com. Retrieved 2017-12-11.
- ^ a b "Announcing the Microsoft Quantum Development Kit". Retrieved 2017-12-11.
- ^ "Solving the quantum many-body problem with artificial neural networks". Microsoft Azure Quantum. 15 February 2017.
- ^ Scott Aaronson's blog, 2013, 'Microsoft: From QDOS to QMA in less than 35 years', https://scottaaronson.blog/?p=1471
- ^ "What are the Q# programming language & QDK? - Azure Quantum". learn.microsoft.com.
- ^ "Microsoft announces quantum computing programming language". Retrieved 2017-12-14.
- ^ Microsoft is open-sourcing its Quantum Development Kit
- ^ "The Women of QuArC". 30 March 2019.
- ^ "Intro to Q# - Intro to Quantum Software Development". stem.mitre.org.
- ^ QuantumWriter. "Setting up the Q# development environment". docs.microsoft.com. Retrieved 2017-12-14.
- ^ Akdogan, Erman (23 October 2022). "Quantum computing is coming for finance & crypto". Medium.
- ^ "This Week in Programming: Get Quantum with Q Sharp". The New Stack. 16 December 2017.
- ^ "Qubit Gate - an overview". www.sciencedirect.com.
- ^ "Microsoft previews quantum computing development kit". CIO.
- ^ "Types in Q# - Microsoft Quantum". docs.microsoft.com.