Ways to run a Q# program
One of the Quantum Development Kit's greatest strengths is its flexibility across platforms and development environments. However, this flexibility also means that new Q# users may find themselves confused or overwhelmed by the numerous options found in the install guide. This page explains what happens when a Q# program is run and compares the different ways in which users can do so.
A primary distinction is that Q# can be run:
- as a standalone application, where Q# is the only language involved and the program is invoked directly. Two methods actually fall in this category:
- the command-line interface
- Q# Jupyter Notebooks
- with an extra host program, written in Python or a .NET language (for example, C# or F#), which then invokes the program and can further process returned results.
To understand these processes and their differences better, let's consider a Q# program and compare the ways it can be run.
Basic Q# program
A basic quantum program might consist of preparing a qubit in an equal superposition of states $\ket{0}$ and $\ket{1}$, measuring it, and returning the result. The result will be randomly either one of these two states with equal probability. Indeed, this process is at the core of the quantum random number generator quickstart.
In Q#, the random number generation would be performed by the following code:
use q = Qubit(); // allocates qubit for use (automatically in |0>)
H(q); // puts qubit in superposition of |0> and |1>
return MResetZ(q); // measures qubit, returns result (and resets it to |0> before deallocation)
However, this code alone can't be run by Q#. To run it needs to make up the body of an operation, which is then run when called---either directly or by another operation. Hence, you can write an operation of the following form:
operation MeasureSuperposition() : Result {
use q = Qubit(); // allocates qubit for use (automatically in |0>)
H(q); // puts qubit in superposition of |0> and |1>
return MResetZ(q); // measures qubit, returns result (and resets it to |0> before deallocation)
}
You've defined an operation, MeasureSuperposition
, which takes no inputs and returns a value of type Result.
In addition to operations, Q# also allows you to encapsulate deterministic computations into functions. Aside from the determinism guarantee that implies that computations that act on qubits need to be encapsulated into operations rather than functions, there's little difference between operations and functions. We refer to them collectively as callables.
Callable defined in a Q# file
The callable is precisely what's called and run by Q#.
However, it requires a few more additions to comprise a full *.qs
Q# file.
All Q# types and callables, both the ones you define and those intrinsic to the language, are defined within namespaces, which provide each a full name that can then be referenced.
For example, the H
and MResetZ
operations are found in the Microsoft.Quantum.Instrinsic
and Microsoft.Quantum.Measurement
namespaces (part of the Q# Standard Libraries).
As such, they can always be called via their full names, Microsoft.Quantum.Intrinsic.H(<qubit>)
and Microsoft.Quantum.Measurement.MResetZ(<qubit>)
, but always doing this full specification would lead to cluttered code.
Instead, open
statements allow callables to be referenced with more concise shorthand, as it's done in the operation body above.
The full Q# file containing our operation would therefore consist of defining our own namespace, opening the namespaces for the callables our operation uses, and then the operation:
namespace Superposition {
open Microsoft.Quantum.Intrinsic; // for the H operation
open Microsoft.Quantum.Measurement; // for MResetZ
operation MeasureSuperposition() : Result {
use q = Qubit(); // allocates qubit for use (automatically in |0>)
H(q); // puts qubit in superposition of |0> and |1>
return MResetZ(q); // measures qubit, returns result (and resets it to |0> before deallocation)
}
}
Note
Namespaces can also be aliased when opened, which can be helpful if callable/type names in two namespaces conflict.
For example, one could instead use open Microsoft.Quantum.Instrinsic as NamespaceWithH;
above, and then call H
via NamespaceWithH.H(<qubit>)
.
Note
One exception to all of this is the Microsoft.Quantum.Core
namespace, which is always automatically opened.
Therefore, callables like Length
can always be used directly.
Running on target machines
Now the general run model of a Q# program becomes clear.

The specific callable to be run has access to any other callables and types defined in the same namespace.
It also accesses those items from any of the Q# libraries, but those items must be referenced either via their full name, or by using open
statements described above.
The callable itself is then run on a target machine.
Such target machines can be actual quantum hardware or the multiple simulators available as part of the QDK.
For the purposes here, the most useful target machine is an instance of the full-state simulator, QuantumSimulator
, which calculates the program's behavior as if it were being run on a noise-free quantum computer.
So far, you've seen what happens when a specific Q# callable is being run. Regardless of whether Q# is used in a standalone application or with a host program, this general process is more or less the same---hence the QDK's flexibility. The differences between the ways of calling into the Quantum Development Kit therefore reveal themselves in how that Q# callable is invoked, and in what manner any results are returned. More specifically, the differences revolve around:
- Indicating which Q# callable is to be run
- How potential callable arguments are provided
- Specifying the target machine on which to run it
- How any results are returned
In the following sections, you'll learn how this is done with the Q# standalone application from the command prompt. Then you'll proceed to using Python and C# host programs. The standalone application of Q# Jupyter Notebooks will be reserved for last, because unlike the first three, its primary functionality doesn't center around a local Q# file.
Note
Although it is not illustrated in these examples, one commonality between the run methods is that any messages printed from inside the Q# program (by way of Message
or DumpMachine
, for example) will typically always be printed to the respective console.
Q# from the command prompt
One of the easiest ways to get started writing Q# programs is to avoid worrying about separate files and a second language altogether. Using Visual Studio Code or Visual Studio with the QDK extension allows for a seamless work flow in which we run Q# callables from only a single Q# file.
For this, you'll ultimately run the program by entering
dotnet run
at the command prompt.
The simplest workflow is when the terminal's directory location is the same as the Q# file, which can be easily handled alongside Q# file editing by using the integrated terminal in VS Code, for example.
However, the dotnet run
command accepts numerous options, and the program can also be run from a different location by providing --project <PATH>
with the location of the Q# file.
Add entry point to Q# file
Most Q# files will contain more than one callable, so naturally we need to let the compiler know which callable to run when we provide the dotnet run
command.
This specification is done with a simple change to the Q# file itself; you need to add a line with @EntryPoint()
directly preceding the callable.
The file from above would therefore become:
namespace Superposition {
open Microsoft.Quantum.Intrinsic; // for the H operation
open Microsoft.Quantum.Measurement; // for MResetZ
@EntryPoint()
operation MeasureSuperposition() : Result {
use q = Qubit(); // allocates qubit for use (automatically in |0>)
H(q); // puts qubit in superposition of |0> and |1>
return MResetZ(q); // measures qubit, returns result (and resets it to |0> before deallocation)
}
}
Now, a call of dotnet run
from the command prompt leads to MeasureSuperposition
being run, and the returned value is then printed directly to the terminal.
So, you'll see either One
or Zero
printed.
It doesn't matter if you have more callables defined below it, only MeasureSuperposition
will be run.
Additionally, it's no problem if your callable includes documentation comments before its declaration, the @EntryPoint()
attribute can be placed above them.
Callable arguments
So far, this article has only considered an operation that takes no inputs. Suppose you wanted to perform a similar operation, but on multiple qubits---the number of which is provided as an argument. Such an operation can be written as:
namespace MultiSuperposition {
open Microsoft.Quantum.Intrinsic; // for the H operation
open Microsoft.Quantum.Measurement; // for MResetZ
open Microsoft.Quantum.Canon; // for ApplyToEach
open Microsoft.Quantum.Arrays; // for ForEach
@EntryPoint()
operation MeasureSuperpositionArray(n : Int) : Result[] {
use qubits = Qubit[n]; // allocate a register of n qubits in |0>
ApplyToEach(H, qubits); // apply H to each qubit in the register
return ForEach(MResetZ, qubits); // perform MResetZ on each qubit, returns the resulting array
}
}
where the returned value is an array of the measurement results.
The ApplyToEach
and ForEach
are in the Microsoft.Quantum.Canon
and Microsoft.Quantum.Arrays
namespaces, requiring another open
statement for each.
If one moves the @EntryPoint()
attribute to precede this new operation (note there can only be one such line in a file), attempting to run it with simply dotnet run
results in an error message that indicates what command-line options are required, and how to express them.
The general format for the command line is actually dotnet run [options]
, and callable arguments are provided there.
In this case, the argument n
is missing, and it shows that we need to provide the option -n <n>
.
To run MeasureSuperpositionArray
for n=4
qubits, you need to run:
dotnet run -n 4
yielding an output similar to
[Zero,One,One,One]
This of course extends to multiple arguments.
Note
Argument names defined in camelCase
are slightly altered by the compiler to be accepted as Q# inputs.
For example, if instead of n
, you decided to use the name numQubits
above, then this input would be provided in the command line via --num-qubits 4
instead of -n 4
.
The error message also provides other options that can be used, including how to change the target machine.
Different target machines
As the outputs from our operations thus far have been the expected results of their action on real qubits, it's clear that the default target machine from the command line is the full-state quantum simulator, QuantumSimulator
.
However, callables can be instructed to run on a specific target machine with the option --simulator
(or the shorthand -s
).
Command line run summary

Non-Q# dotnet run
options
As it's briefly mentioned above with the --project
option, the dotnet run
command also accepts options unrelated to the Q# callable arguments.
If providing both kinds of options, the dotnet
-specific options must be provided first, followed by a delimiter --
, and then the Q#-specific options.
For example, specifying a path along with a number of qubits for the operation above would be run via dotnet run --project <PATH> -- -n <n>
.
Q# with host programs
With the Q# file in hand, an alternative to calling an operation or function directly from the command prompt is to use a host program in another classical language. Specifically, this invocation can be done with either Python or a .NET language such as C# or F# (for the sake of brevity we'll only detail C# here). A little more setup is required to enable the interoperability, but those details can be found in the install guides.
In a nutshell, the situation now includes a host program file (for example, *.py
or *.cs
) in the same location as our Q# file.
It's now the host program that gets run. While it's running, it can call specific Q# operations and functions from the Q# file.
The core of the interoperability is based on the Q# compiler making the contents of the Q# file accessible to the host program so that they can be called.
One of the main benefits of using a host program is that the classical data returned by the Q# program can then be further processed in the host language. This handling could consist of some advanced data processing, for example, something that can't be done internally in Q#, and then calling further Q# actions based on those results, or something as simple as plotting the Q# results.
The general scheme is shown down here, and the discussion of the specific implementations for Python and C# is below. A sample using an F# host program can be found at the .NET interoperability samples.

Note
The @EntryPoint()
attribute used for Q# applications cannot be used with host programs.
An error will be raised if it is present in the Q# file being called by a host.
To work with different host programs, there are no changes required to a *.qs
Q# file.
The following host program implementations all work with the same Q# file:
namespace Superposition {
open Microsoft.Quantum.Intrinsic; // for H
open Microsoft.Quantum.Measurement; // for MResetZ
open Microsoft.Quantum.Canon; // for ApplyToEach
open Microsoft.Quantum.Arrays; // for ForEach
operation MeasureSuperposition() : Result {
use q = Qubit(); // allocates qubit for use (automatically in |0>)
H(q); // puts qubit in superposition of |0> and |1>
return MResetZ(q); // measures qubit, returns result (and resets it to |0> before deallocation)
}
operation MeasureSuperpositionArray(n : Int) : Result[] {
use qubits = Qubit[n];
ApplyToEach(H, qubits);
return ForEach(MResetZ, qubits);
}
}
Select the tab corresponding to your host language of interest.
A Python host program is constructed as follows:
Import the
qsharp
module, which registers the module loader for Q# interoperability. This import allows Q# namespaces to appear as Python modules, from which we can "import" Q# callables. It's technically not the Q# callables themselves that are imported, but rather Python stubs that allow calling into them. These stubs behave as objects of Python classes. One uses methods on these objects to specify the target machines that the operation is sent to when running the program.Import those Q# callables that we'll directly invoke---in this case,
MeasureSuperposition
andMeasureSuperpositionArray
.import qsharp from Superposition import MeasureSuperposition, MeasureSuperpositionArray
With the
qsharp
module imported, you can also import callables directly from the Q# library namespaces.Alongside regular Python code, you can now run those callables on specific target machines, and assign their return values to variables for further use:
random_bit = MeasureSuperposition.simulate() print(random_bit)
Diagnostics
As with Q# standalone notebooks, you can also use diagnostics like DumpMachine
and DumpOperation
from Python notebooks to learn how your Q# program work and to help diagnose issues and bugs in your Q# programs.
namespace DumpOperation {
open Microsoft.Quantum.Diagnostics;
operation DumpPlusState() : Unit {
use q = Qubit();
within {
H(q);
} apply {
DumpMachine();
}
}
}
from DumpOperation import DumpPlusState
print(DumpPlusState.simulate())
Calling DumpMachine function generates the following output:
# wave function for qubits with ids (least to most significant): 0
∣0❭: 0.707107 + 0.000000 i == *********** [ 0.500000 ] --- [ 0.00000 rad ]
∣1❭: 0.707107 + 0.000000 i == *********** [ 0.500000 ] --- [ 0.00000 rad ]
The Q# package also allows you to capture these diagnostics and manipulate them as Python objects:
with qsharp.capture_diagnostics() as diagnostics:
DumpPlusState.simulate()
print(diagnostics)
[{'diagnostic_kind': 'state-vector',
'div_id': 'dump-machine-div-7d3eac24-85c5-4080-b123-4a76cacaf58f',
'qubit_ids': [0],
'n_qubits': 1,
'amplitudes': [{'Real': 0.7071067811865476,
'Imaginary': 0.0,
'Magnitude': 0.7071067811865476,
'Phase': 0.0},
{'Real': 0.7071067811865476,
'Imaginary': 0.0,
'Magnitude': 0.7071067811865476,
'Phase': 0.0}]}]
Working with raw JSON for diagnostics can be inconvenient, so the capture_diagnostics function also supports converting diagnostics into quantum objects using the QuTiP library:
with qsharp.capture_diagnostics(as_qobj=True) as diagnostics:
DumpPlusState.simulate()
diagnostics[0]
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[0.707]
[0.707]]
To learn more about the diagnostics features offered by Q# and the Quantum Development Kit, see testing and debugging.
Specifying target machines
Running Q# operations on a specific target machine is done by invoking Python methods directly on the imported operation object. Thus, there's no need to create an object for the run target (such as a simulator). Instead, invoke one of the following methods to run the imported Q# operation:
.simulate(<args>)
uses the full state simulator to simulate the operation for an ideal quantum computer. (API reference for.simulate()
)..simulate_sparse(<args>)
uses the sparse simulator to simulate the operation for an ideal quantum computer. (API reference for.simulate_sparse()
)..toffoli_simulate(<args>)
uses the Toffoli simulator to provide a more efficient simulation method for a restricted class of quantum programs. (API reference for.toffoli_simulate()
)..simulate_noise(<args>)
uses the noise simulator to simulate the operation in an open quantum system under the influence of noise. You can enable the use of the noise simulator by callingqsharp.experimental.enable_noisy_simulation()
.
For more information about local target machines, see Quantum simulators.
Passing arguments to callables in Q#
Arguments for the Q# callable should be provided in the form of a keyword argument, where the keyword is the argument name in the Q# callable definition.
That is, MeasureSuperpositionArray.simulate(n=4)
is valid, whereas MeasureSuperpositionArray.simulate(4)
would throw an error.
Therefore, the Python host program
import qsharp
from Superposition import MeasureSuperposition, MeasureSuperpositionArray
single_qubit_result = MeasureSuperposition.simulate()
single_qubit_resources = MeasureSuperposition.estimate_resources()
multi_qubit_result = MeasureSuperpositionArray.simulate(n=4)
multi_qubit_resources = MeasureSuperpositionArray.estimate_resources(n=4)
print('Single qubit:\n' + str(single_qubit_result))
print(single_qubit_resources)
print('\nMultiple qubits:\n' + str(multi_qubit_result))
print(multi_qubit_resources)
results in an output as follows:
Single qubit:
1
{'CNOT': 0, 'QubitClifford': 1, 'R': 0, 'Measure': 1, 'T': 0, 'Depth': 0, 'Width': 1, 'BorrowedWidth': 0}
Multiple qubits:
[0, 1, 1, 1]
{'CNOT': 0, 'QubitClifford': 4, 'R': 0, 'Measure': 4, 'T': 0, 'Depth': 0, 'Width': 4, 'BorrowedWidth': 0}
Passing arrays in a similar manner is also possible. You can see an example in the Reversible Logic Synthesis sample.
Passing qubits as arguments from classical code isn't possible. Any logic that relates to Q# types like Qubit
should live in your Q# code. If you want your Python code to specify the number of qubits, you could have something like nQubits : Int
parameter to your Q# operation. Your Python code could pass the number of qubits as an integer and then your Q# code could allocate the array of the appropriate number of qubits.
For the Pauli
and Result
types, there are actually Python enums defined such that you could pass those values directly if you want to. See qsharp.Pauli and qsharp.Result.
Using Q# code from other projects or packages
By default, the import qsharp
command loads all of the .qs
files in the current folder and makes their Q# operations and functions
available for use from inside the Python script.
To load Q# code from another folder, the qsharp.projects
API
can be used to add a reference to a .csproj
file for a Q# project (that is, a project that references Microsoft.Quantum.Sdk
).
This command will compile any .qs
files in the folder containing the .csproj
and its subfolders. It will also recursively load
any packages referenced via PackageReference
or Q# projects referenced via ProjectReference
in that .csproj
file.
As an example, the following Python code imports an external project, referencing its path relative to the current folder, and invokes one of its Q# operations:
import qsharp
qsharp.projects.add("../qrng/Qrng.csproj")
from Qrng import SampleQuantumRandomNumberGenerator
print(f"Qrng result: {SampleQuantumRandomNumberGenerator.simulate()}")
This code results in output as follows:
Adding reference to project: ../qrng/Qrng.csproj
Qrng result: 0
To load external packages containing Q# code, use the qsharp.packages
API.
If the Q# code in the current folder depends on external projects or packages, you may see errors when running import qsharp
,
since the dependencies have not yet been loaded.
To load required external packages or Q# projects during the import qsharp
command, ensure that the folder with the Python script
contains a .csproj
file that references Microsoft.Quantum.Sdk
. In that .csproj
, add the property
<IQSharpLoadAutomatically>true</IQSharpLoadAutomatically>
to the <PropertyGroup>
. This change will instruct IQ# to recursively
load any ProjectReference
or PackageReference
items found in that .csproj
during the import qsharp
command.
For example, here is a simple .csproj
file that causes IQ# to automatically load the Microsoft.Quantum.Chemistry
package:
<Project Sdk="Microsoft.Quantum.Sdk/0.17.2105143879">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netstandard2.1</TargetFramework>
<IQSharpLoadAutomatically>true</IQSharpLoadAutomatically>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Chemistry" Version="0.17.2105143879" />
</ItemGroup>
</Project>
Note
Currently this custom <IQSharpLoadAutomatically>
property is required by Python hosts, but in the future,
this may become the default behavior for a .csproj
file located in the same folder as the Python script.
Note
Currently the <QsharpCompile>
setting in the .csproj
is ignored by Python hosts, and all .qs
files
in the folder of the .csproj
(including subfolders) are loaded and compiled. Support for .csproj
settings will be improved in the future
(for more information, see iqsharp#277).
Feedback
Submit and view feedback for