Python features in kernel scope#
Quadrants kernels are compiled to GPU machine code, so only a subset of Python is supported inside @qd.kernel and @qd.func functions. This page documents what works, what doesn’t, and common workarounds.
Supported#
The following Python features work inside kernels:
Arithmetic operators:
+,-,*,/,//,%,**Comparison operators:
<,<=,>,>=,==,!=Logical operators:
and,or,notBitwise operators:
&,|,^,~,<<,>>Augmented assignment:
+=,-=,*=, etc. (note: these are atomic)if/elif/elseforloops overrange(),qd.ndrange(),qd.grouped(), orqd.static()whileloopsbreakandcontinuein non-parallelized loops (inner loops,whileloops)assert(whendebug=Trueis passed toqd.init())print(for scalar values) (not on Metal)Local variables (scalars, vectors, matrices)
Lists and tuples (as compile-time containers, e.g.
[1, 2, 3])F-strings (limited: scalar values only)
Type casts:
int(),float()
Not supported#
The following Python features will raise errors or produce unexpected behavior inside kernels:
Statements#
Feature |
Error |
|---|---|
|
Compilation error |
|
|
|
|
|
|
|
|
|
|
|
|
Function definitions inside kernels |
|
Class definitions |
|
|
|
|
|
Expressions and operators#
Feature |
Error |
|---|---|
|
|
|
Compilation error |
Sets ( |
Compilation error |
|
|
Types and data structures#
Feature |
Notes |
|---|---|
Strings |
No string manipulation; only literal strings in |
Dictionaries |
Only as compile-time constants via |
Classes / objects |
Cannot define or instantiate arbitrary Python classes |
Generators |
Not supported |
|
Only in a narrow case |
Control flow restrictions#
returninside non-staticif/for: not allowed in@qd.func(allowed in@qd.real_func)breakin the outermost (parallelized) for loop: not allowed — the outermost loop is mapped to GPU threadsbreak/continuein a staticforinside a non-staticif: not allowedReassigning kernel arguments: kernel parameters are immutable; create a local copy instead
Common workarounds#
Use qd.static() for compile-time Python logic#
If you need Python-level logic (dictionaries, complex conditionals, etc.), wrap it in qd.static() so it’s evaluated at compile time:
options = {"mode_a": 1, "mode_b": 2}
selected = "mode_a"
@qd.kernel
def compute(a: qd.Template) -> None:
val = qd.static(options[selected])
a[0] = val
Local copy for immutable arguments#
@qd.kernel
def compute(n: int, a: qd.Template) -> None:
local_n = n # can now modify local_n
local_n += 1
Argument unpacking#
Syntax like some_function(*args) is supported in a narrow case:
*argsmust be the last argument in the function call*argsmust not containdataclasses.dataclassobjects