-
Notifications
You must be signed in to change notification settings - Fork 97
Invoking Q# callables from Python
The qsharp
Python package makes it easy to call Q# operations and functions from within Python. Each Q# callable defined through calls to qsharp.eval()
or in a Q# project loaded via qsharp.init()
is automatically added to the qsharp.code
module in Python:
import qsharp
qsharp.eval("""
operation Superposition() : Result {
use q = Qubit();
H(q);
Std.Diagnostics.DumpMachine();
MResetZ(q)
}
""")
qsharp.code.Superposition()
STATE:
|0⟩: 0.7071+0.0000𝑖
|1⟩: 0.7071+0.0000𝑖
One
The same is true for Q# callables defined in Jupyter notebook using the %%qsharp
cell magic:
These callables can then be invoked as normal Python functions, which will run them in the Q# simulator just as if they were invoked from within a normal Q# context. Any output produced from calls to Message
or diagnostics like DumpMachine
will appear as normal and the return from the function marshalled into Python:
These callables can also be imported within the Python environment:
Python literals and variables can be passed directly to Q# callables like any other Python function, and types that support conversion into the equivalent Q# types will work as expected:
Python wrappers around Q# callables can also be passed to the qsharp.run()
function to simulate them across multiple shots. Simply pass the relevant Python callable as the first parameter, the number of shots as the second, and any arguments to the callable as additional arguments to run
:
qsharp.eval(
'operation Foo(nResults : Int) : Result[] { Repeated(Zero, nResults) }'
)
qsharp.run(qsharp.code.Foo, 3, 2)
[[Zero, Zero], [Zero, Zero], [Zero, Zero]]
Callables can also be provided to qsharp.estimate()
to trigger the Azure Quantum Resource Estimator. Like with qsharp.run()
above, the first parameter can be a Callable from qsharp.code
(either explicitly referenced or previously imported). The arguments to the Q# Callable must appear after the estimation parameters and before any named arguments to be picked up as variadic arguments:
qsharp.eval(
"""
operation Test(nQubits : Int) : Unit {
use qs = Qubit[nQubits];
for q in qs {
T(q);
M(q);
}
}
"""
)
res = qsharp.estimate(qsharp.code.Test, params, 7)
Callables can also be used with qsharp.circuit()
to generate a circuit description for the given arguments. These can then be displayed with the circuit widget:
Python wrappers around Q# callables can also be used with qsharp.compile()
to generate QIR. The QIR compilation will use the provided arguments from Python, making it easier to iterate over different parameters for different compilations. For example, this code uses a Q# operation with a paramter for the number of qubits and passes that as an argument from Python:
qsharp.init(target_profile=qsharp.TargetProfile.Base)
qsharp.eval(
"operation Program(nQubits : Int) : Result[] { use qs = Qubit[nQubits]; MResetEachZ(qs) }"
)
qir = qsharp.compile(qsharp.code.Program, 5)
If a Python value cannot be converted into the correct Q# type or the wrong number of arguments are provided, an exception is raised:
Not all Q# types support conversion from/to Python; if a callable has arguments or return values of these types, invoking the function will trigger a runtime exception:
Unsupported interop types include Qubits, structs/user-defined-types, and other callables.
When using projects, Q# callables will be with a module hierarchy matching the namespace hierarchy of the project:
When qsharp.init()
is called the current compilation and simulator state is reset, so all callables are removed from the qsharp.code
module:
Any functions previously imported from qsharp.code
are also invalidated: