Programs¶
A Qoala program is a Python callable annotated such that euqalyptus can intercept its body and emit Qoala HIR. There are two equivalent ways to declare one.
@QoalaProgram — the decorator¶
from euqalyptus import QoalaProgram
@QoalaProgram
def my_program():
...
The decorator wraps your function in an instance with .compile() and .module accessors. Calling the decorated object is equivalent to calling .compile():
ret_val, module = my_program() # equivalent to my_program.compile()
ret_val, module = my_program.compile()
After a successful compile, my_program.module returns the QoalaModule. Accessing it before compilation raises NotYetCompiledError.
QoalaProgramBase — the class¶
from euqalyptus import QoalaProgramBase
class MyProgram(QoalaProgramBase):
def main(self):
...
You implement main(self), then instantiate and compile:
program = MyProgram()
ret_val, module = program.compile()
Quirky __new__
QoalaProgramBase.__new__ uses some hacks to wire cls.main as the entry function. As a result, an instance of a subclass of QoalaProgramBase is not an instance of QoalaProgramBase — it is an instance of QoalaProgram. Don't rely on isinstance(obj, QoalaProgramBase).
If main is missing or remains @abstractmethod, instantiation raises QuantumProgramNotImplementedError.
When to use which¶
| Decorator | Class | |
|---|---|---|
| Single-shot scripts | ✓ | |
| You need state across compilations | ✓ | |
| Inheritance for a family of related programs | ✓ | |
| You want the program to also be callable as a regular function | ✓ (via compile()) |
|
| Importable in tests as one symbol | both | both |
For most short examples, the decorator is the natural fit. The class form starts to pay off when you have a couple of different programs that share helpers — for instance, the teleportation example is two near-identical programs that could share a base class.
What the entry function may contain¶
Inside the body of a @QoalaProgram (or a main method), the SDK objects don't actually do their operation directly — they record an AST node into the active program's module. Conceptually:
@QoalaProgram
def example():
# Declares a remote symbol; recorded into the AST.
Remote("Bob")
# Records a qnet.eprs / qnet.new_qubit op into the current function body.
q = Entangle("Bob")
# Records a qnet.measure op; m is a QoalaInteger AST node, not a Python int.
m = q.measure()
This is why operations in qoala programs look like ordinary Python: the SDK is using constructors and methods to build the IR. You can mix in regular Python control structures (loops over compile-time values, helper functions, …) freely — anything that is evaluated before or after the SDK calls is just regular Python. What you cannot do is treat the runtime SDK values (such as m above) as plain Python values: comparing m == 0 returns a recorded comparison expression, not a boolean. For control flow that depends on runtime values, see Branching.
After compilation¶
The QoalaModule returned from .compile() exposes the textual HIR via module.asm (the canonical input to qoala-opt) and the generic-form variant via module.generic_asm. The full list of recorded functions is reachable through module.functions, the remote declarations encountered during compilation through module.remotes, and the function currently being built (useful for introspection mid-compile, less so afterward) through module.current_function. For details on compile()'s arguments and what the module exposes, see Compilation.
API reference¶
QoalaProgram ¶
QoalaProgram(entry_fun: Callable)
Decorator that turns a Python function into a Qoala program.
Applying @QoalaProgram to a function marks it as a Qoala
program. The decorator wraps the function in an object that
exposes a :meth:compile method; calling compile() runs the
decorated function under the SDK's recording mode and produces a
:class:QoalaModule containing Qoala HIR.
Example
@QoalaProgram
def my_function():
q = LocalQubit()
q.measure()
_, module = my_function.compile()
print(module.asm)
Calling the decorated object is equivalent to calling
.compile() on it; my_function() and my_function.compile()
both return the same (return_value, QoalaModule) tuple.
module
property
¶
module: QoalaModule
The compiled :class:QoalaModule.
Returns:
| Type | Description |
|---|---|
QoalaModule
|
The module produced by the most recent successful call to |
QoalaModule
|
meth: |
Raises:
| Type | Description |
|---|---|
NotYetCompiledError
|
If :meth: |
compile ¶
compile(*args: Any, compile_lazy: bool = False, singular_comm_ops: bool = False, **kwargs: Any) -> Tuple[int, QoalaModule]
Compile the decorated program into a Qoala HIR module.
compile() runs the decorated function under the SDK's
recording mode, so every SDK call inside the function body is
intercepted and recorded as an AST node rather than performing
its nominal action. Once the function returns, the recorded
AST is walked and emitted as MLIR via the qnet Python
bindings, yielding a :class:QoalaModule whose .asm
property is the textual HIR consumable by qoala-opt.
compile() acquires a process-wide lock and uses class-level
state on :class:QoalaProgram to track the program currently
being compiled, so two programs cannot be compiled
concurrently from the same process — calls serialize.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Any
|
Positional arguments forwarded to the entry function. |
()
|
compile_lazy
|
bool
|
When |
False
|
singular_comm_ops
|
bool
|
When |
False
|
**kwargs
|
Any
|
Keyword arguments forwarded to the entry function. |
{}
|
Returns:
| Type | Description |
|---|---|
int
|
A tuple |
QoalaModule
|
is whatever the entry function returned (often |
Tuple[int, QoalaModule]
|
and |
compile_lazy_flag
classmethod
¶
compile_lazy_flag(new_flag_value: Optional[bool] = None) -> bool
Get or set the class-level compile_lazy toggle.
When set, subsequent calls to :meth:compile skip the
MLIR-emission stage by default and build only the internal
pseudo-AST. Useful in tests and repeated-compilation harnesses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_flag_value
|
Optional[bool]
|
When not |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
The current value of the toggle (after the optional set). |
compile_singular_comm_ops
classmethod
¶
compile_singular_comm_ops(new_flag_value: Optional[bool] = None) -> bool
Get or set the class-level singular_comm_ops toggle.
When set, subsequent calls to :meth:compile emit the scalar
HIR ops (qnet.send_int, qnet.send_float) for
single-value classical sends instead of their tensor-form
counterparts. The flag does not affect receives — see
:meth:compile for the full discussion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_flag_value
|
Optional[bool]
|
When not |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
The current value of the toggle (after the optional set). |
current_function
classmethod
¶
current_function() -> QoalaFunction
Return the :class:QoalaFunction currently being built.
Used by the SDK constructors to find the function they should record into; rarely useful in user code.
Returns:
| Type | Description |
|---|---|
QoalaFunction
|
The active program's current function. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no program is currently being compiled. |
get_declared_remote
classmethod
¶
get_declared_remote(remote_name: str) -> Any
Look up a previously declared remote by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
remote_name
|
str
|
The symbolic name of the remote peer. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
The |
Any
|
class: |
Any
|
one was declared in the current compilation, otherwise |
|
Any
|
|
add_declared_remote
classmethod
¶
add_declared_remote(remote_name: str, remote: Any) -> None
Register a remote-peer declaration in the current compilation.
Used internally by :class:~euqalyptus.operations.Remote to
record a new alias; user code should call Remote("Name")
instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
remote_name
|
str
|
The symbolic name of the remote. |
required |
remote
|
Any
|
The :class: |
required |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If a remote with the same name has already been declared in this compilation. |
QoalaProgramBase ¶
QoalaProgramBase(entry_fun: Callable)
Bases: QoalaProgram, ABC
Class-based alternative to the @QoalaProgram decorator.
Subclass QoalaProgramBase and implement the abstract
:meth:main method to define a Qoala program. Instantiating the
subclass and calling .compile() runs main under the SDK's
recording mode, just like the decorator form.
Example
class MyProgram(QoalaProgramBase):
def main(self):
q = LocalQubit()
q.measure()
program = MyProgram()
_, module = program.compile()
Warning
Due to the way __new__ is wired, an instance of a subclass
of QoalaProgramBase is not an instance of
QoalaProgramBase — it is an instance of
:class:QoalaProgram. Do not rely on
isinstance(obj, QoalaProgramBase).
main
abstractmethod
¶
main(*args: Any, **kwargs: Any) -> Any
Entry point of a class-based Qoala program.
Subclasses must implement this method. Inside its body you can
use any quantum or classical primitive from the
euqalyptus package — types, qubit operations, communication,
and control-flow constructs — just as you would inside a
@QoalaProgram decorated function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Any
|
Positional arguments forwarded by
:meth: |
()
|
**kwargs
|
Any
|
Keyword arguments forwarded by
:meth: |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
Whatever value the program wants to return to the caller |
Any
|
(typically classical measurement outcomes or |
Any
|
The returned value becomes the first element of the |
Any
|
|
Any
|
meth: |