Q# works in conjunction with classical languages such as C#, Python and F#, and is designed to allow the use of traditional programming concepts in quantum computing, including functions with variables and branches as well as a syntax-highlighted development environment with a quantum debugger.[1][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.[10] On December 11, 2017, Microsoft released Q# as a part of the Quantum Development Kit.[4]
At Build 2019, Microsoft announced that it would be open-sourcing the Quantum Development Kit, including its Q# compilers and simulators.[11]
To support Q#, Microsoft developed Quantum Intermediate Representation (QIR) in 2023 as a common interface between programming languages and target quantum processors. The company also announced a compiler extension that generates QIR from Q#.[12]
Q# is available as a separately downloaded extension for Visual Studio,[15] but it can also be run as an independent tool from the command line or Visual Studio Code. Q# was introduced on Windows and is available on MacOS and Linux.[16]
The Quantum Development Kit includes a quantum simulator capable of running Q# and simulated 30 logical qubits.[17][18]
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.[19]
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.[21]
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, called 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.
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 of void, an empty Tuple() is returned.
Definition of record datatypes (using the newtype keyword, instead of type).
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.namespaceMicrosoft.Quantum.Canon{openMicrosoft.Quantum.Intrinsic;openMicrosoft.Quantum.Arithmetic;openMicrosoft.Quantum.Arrays;openMicrosoft.Quantum.Diagnostics;openMicrosoft.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)operationMultiplexOperationsFromGenerator<'T>(unitaryGenerator:(Int,(Int->('T=>UnitisAdj+Ctl))),index:LittleEndian,target:'T):UnitisCtl+Adj{let(nUnitaries,unitaryFunction)=unitaryGenerator;letunitaryGeneratorWithOffset=(nUnitaries,0,unitaryFunction);ifLength(index!)==0{fail"MultiplexOperations failed. Number of index qubits must be greater than 0.";}ifnUnitaries>0{letauxiliary=[];AdjointMultiplexOperationsFromGeneratorImpl(unitaryGeneratorWithOffset,auxiliary,index,target);}}/// # Summary/// Implementation step of `MultiplexOperationsFromGenerator`./// # See Also/// - Microsoft.Quantum.Canon.MultiplexOperationsFromGeneratorinternaloperationMultiplexOperationsFromGeneratorImpl<'T>(unitaryGenerator:(Int,Int,(Int->('T=>UnitisAdj+Ctl))),auxiliary:Qubit[],index:LittleEndian,target:'T):Unit{body(...){letnIndex=Length(index!);letnStates=2^nIndex;let(nUnitaries,unitaryOffset,unitaryFunction)=unitaryGenerator;letnUnitariesLeft=MinI(nUnitaries,nStates/2);letnUnitariesRight=MinI(nUnitaries,nStates);letleftUnitaries=(nUnitariesLeft,unitaryOffset,unitaryFunction);letrightUnitaries=(nUnitariesRight-nUnitariesLeft,unitaryOffset+nUnitariesLeft,unitaryFunction);letnewControls=LittleEndian(Most(index!));ifnUnitaries>0{ifLength(auxiliary)==1andnIndex==0{// Termination case(ControlledAdjoint(unitaryFunction(unitaryOffset)))(auxiliary,target);}elifLength(auxiliary)==0andnIndex>=1{// Start caseletnewauxiliary=Tail(index!);ifnUnitariesRight>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.letcontrols=[Tail(index!)]+auxiliary;usenewauxiliary=Qubit();useandauxiliary=Qubit[MaxI(0,Length(controls)-2)];within{ApplyAndChain(andauxiliary,controls,newauxiliary);}apply{ifnUnitariesRight>0{MultiplexOperationsFromGeneratorImpl(rightUnitaries,[newauxiliary],newControls,target);}within{(ControlledX)(auxiliary,newauxiliary);}apply{MultiplexOperationsFromGeneratorImpl(leftUnitaries,[newauxiliary],newControls,target);}}}}}adjointauto;controlled(controlRegister,...){MultiplexOperationsFromGeneratorImpl(unitaryGenerator,auxiliary+controlRegister,index,target);}adjointcontrolledauto;}/// # 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.operationMultiplexOperationsBruteForceFromGenerator<'T>(unitaryGenerator:(Int,(Int->('T=>UnitisAdj+Ctl))),index:LittleEndian,target:'T):UnitisAdj+Ctl{letnIndex=Length(index!);letnStates=2^nIndex;let(nUnitaries,unitaryFunction)=unitaryGenerator;foridxOpin0..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.MultiplexOperationsFromGeneratorfunctionMultiplexerFromGenerator(unitaryGenerator:(Int,(Int->(Qubit[]=>UnitisAdj+Ctl)))):((LittleEndian,Qubit[])=>UnitisAdj+Ctl){returnMultiplexOperationsFromGenerator(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.MultiplexOperationsBruteForceFromGeneratorfunctionMultiplexerBruteForceFromGenerator(unitaryGenerator:(Int,(Int->(Qubit[]=>UnitisAdj+Ctl)))):((LittleEndian,Qubit[])=>UnitisAdj+Ctl){returnMultiplexOperationsBruteForceFromGenerator(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.internaloperationApplyAndChain(auxRegister:Qubit[],ctrlRegister:Qubit[],target:Qubit):UnitisAdj{ifLength(ctrlRegister)==0{X(target);}elifLength(ctrlRegister)==1{CNOT(Head(ctrlRegister),target);}else{EqualityFactI(Length(auxRegister),Length(ctrlRegister));letcontrols1=ctrlRegister[0..0]+auxRegister;letcontrols2=Rest(ctrlRegister);lettargets=auxRegister+[target];ApplyToEachA(ApplyAnd,Zipped3(controls1,controls2,targets));}}}