Qubit operations¶
Every method documented here is defined on the Qubit base class and inherited by LocalQubit, EntangledQubit, and ScopedQubit. Calling a method records the corresponding HIR op into the active program's body.
Source: euqalyptus/types/quantum/qubit.py.
Single-qubit Pauli and Clifford gates¶
| Method | HIR op | Notes |
|---|---|---|
q.X() |
qnet.x |
Pauli X (Hermitian). |
q.Y() |
qnet.y |
Pauli Y (Hermitian). |
q.Z() |
qnet.z |
Pauli Z (Hermitian). |
q.H() |
qnet.hadamard |
Hadamard (Hermitian). |
q.T() |
rotation form | π/4 around Z. Lowered through the angle-discretization machinery. |
q.S() |
rotation form | π/2 around Z. |
q.K() |
rotation form | Maps |0⟩ to +|i⟩ (positive Y) and vice versa. |
q = LocalQubit()
q.H()
q.X()
Single-qubit rotations¶
rot_X, rot_Y, and rot_Z accept either an integer-pair (n, d) encoding angle = n·π / 2^d, or an explicit floating-point angle=:
q.rot_X(n=1, d=2) # π/4 rotation around X
q.rot_Y(angle=0.7853981633974483) # explicit float angle
Signature for all three:
def rot_X(
self,
n: int | QoalaIntegerType = 0,
d: int | QoalaIntegerType = 0,
angle: float | QoalaFloatingPointType | None = None,
) -> None:
...
If angle is provided, n and d are ignored and the SDK records a qnet.rot_* (float-angle) op. The angle is later discretized — at MIR level, lower-float-rotations rewrites it to qmem.rot_*_int form using the runtime helper if needed. See qoala-mlir / Passes / MIR helpers.
If angle is None, the SDK records qnet.rot_*_int directly with n and d.
Two-qubit gates¶
Methods that take a target qubit:
| Method | HIR op | Notes |
|---|---|---|
q.cnot(target) |
qnet.cnot |
CNOT controlled by q, target target. |
q.cphase(target) |
qnet.cz |
CPHASE / CZ. The two are aliases on the SDK side. |
q.cz(target) |
qnet.cz |
Synonym for cphase. |
ctrl = LocalQubit()
tgt = LocalQubit()
ctrl.cnot(tgt)
crot_X (controlled X-rotation) is not exposed as a method on Qubit. It exists as an op in the dialect but is reachable only through the lowering passes (it appears in MIR/LIR after MIR-level rewrites). If you need a controlled rotation in user code, decompose it manually.
Measurement¶
m = q.measure()
measure is the standard-basis measurement. It records qnet.measure and returns a QoalaIntegerType AST node (effectively a Bit). After this point, the qubit value has been consumed in HIR — using q again is a linearity violation and will fail qnet-check-linear downstream. Reuse the returned AST value (the measurement outcome) instead.
Free¶
q.free()
Marks the qubit as released so its physical slot can be reused. There is no corresponding qnet.* op at HIR level — free() is consumed by the AST builder and surfaces during the MIR lifecycle work. In practice you can ignore it for most short programs; it becomes relevant when you write programs with many qubits and want to control reuse.
Linearity invariant¶
Each qubit value should be consumed at most once. The SDK doesn't enforce this at the Python level (a method call doesn't visibly "consume" self), but qoala-mlir's qnet-check-linear does. If you observe a Use of qubit after consumed error from qoala-opt, it usually means the program reused a qubit value after measure() or after a gate operation that, in HIR, returns a new qubit value.
In SDK terms, the rules of thumb:
- After
q.measure(), do not call any further methods onq. - For operations that take a target (
q.cnot(target)), the recorded op produces fresh qubit values for both — yourqandtargetPython references are kept synced internally, so you don't have to re-bind them.
API reference¶
The qubit-operation methods are defined on the abstract Qubit base class; every concrete qubit type (LocalQubit, EntangledQubit, ScopedQubit) inherits them.
Qubit ¶
Bases: QoalaQuantumType, ABC
Base class for every qubit type exposed by the SDK.
A Qubit instance represents the quantum state stored in a
physical qubit somewhere on the local quantum node. Constructing
a concrete subclass — :class:LocalQubit for a locally-initialized
qubit, :class:EntangledQubit for the local half of an EPR pair,
or :class:ScopedQubit for a qubit that has to survive a branching
region — records the allocation and initialization of that qubit
in QoalaHIR. Gates, rotations, and measurement are performed by
calling the corresponding methods on the qubit value.
Operations follow HIR's value-based semantics: each method records
a new SSA value for the qubit and conceptually "replaces" the
current one. The wrapper objects on the Python side hide this so
you can keep writing q.X(); q.measure() as if q were
mutable.
measure ¶
measure() -> QoalaIntegerType
Measure the qubit in the standard basis.
Records a qnet.measure op on this qubit. The qubit value
is consumed by the call; calling any other method on the same
qubit afterwards will be rejected by the qnet-check-linear
verifier.
Returns:
| Name | Type | Description |
|---|---|---|
A |
QoalaIntegerType
|
class: |
QoalaIntegerType
|
outcome ( |
K ¶
K()
Not implemented. Placeholder for a K gate.
Conceptually, a K gate would move the |0> state to +|i>
(positive Y) and vice versa. In the current SDK implementation
this method is a no-op stub — calling it has no effect and the
gate is not recorded in HIR. Use the rotations or
H/S combinations instead.
rot_X ¶
rot_X(n: int | QoalaIntegerType = 0, d: int | QoalaIntegerType = 0, angle: float | QoalaFloatingPointType | None = None)
Record a rotation around the X axis.
The rotation angle can be given in two ways. With the integer
pair (n, d) it is interpreted as n · π / 2^d radians;
for example, (n, d) = (1, 2) is a π/4 rotation. With the
angle keyword, an arbitrary floating-point angle is taken
directly and discretized later in the pipeline. If angle
is given, n and d are ignored.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int | QoalaIntegerType
|
Numerator of the discrete angle specification. Defaults
to |
0
|
d
|
int | QoalaIntegerType
|
Denominator-exponent of the discrete angle
specification. Defaults to |
0
|
angle
|
float | QoalaFloatingPointType | None
|
Optional explicit floating-point angle, in radians.
Defaults to |
None
|
rot_Y ¶
rot_Y(n: int | QoalaIntegerType = 0, d: int | QoalaIntegerType = 0, angle: float | QoalaFloatingPointType | None = None)
Record a rotation around the Y axis.
Identical to :meth:rot_X but on the Y axis. See that method
for the meaning of n, d, and angle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int | QoalaIntegerType
|
Numerator of the discrete angle specification. |
0
|
d
|
int | QoalaIntegerType
|
Denominator-exponent of the discrete angle specification. |
0
|
angle
|
float | QoalaFloatingPointType | None
|
Optional explicit floating-point angle, in radians. |
None
|
rot_Z ¶
rot_Z(n: int | QoalaIntegerType = 0, d: int | QoalaIntegerType = 0, angle: float | QoalaFloatingPointType | None = None)
Record a rotation around the Z axis.
Identical to :meth:rot_X but on the Z axis. See that method
for the meaning of n, d, and angle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int | QoalaIntegerType
|
Numerator of the discrete angle specification. |
0
|
d
|
int | QoalaIntegerType
|
Denominator-exponent of the discrete angle specification. |
0
|
angle
|
float | QoalaFloatingPointType | None
|
Optional explicit floating-point angle, in radians. |
None
|
cnot ¶
cnot(target: Self) -> None
Record a CNOT gate with this qubit as control and target as target.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Self
|
The target qubit. Must reside on the same node as
this qubit (calling |
required |
cphase ¶
cphase(target: Self) -> None
Record a controlled-Z (CPHASE) gate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Self
|
The target qubit. Must reside on the same node as this qubit. |
required |
cz ¶
cz(target: Self) -> None
Synonym for :meth:cphase. Records a controlled-Z gate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Self
|
The target qubit. Must reside on the same node as this qubit. |
required |
free ¶
free() -> None
Not implemented. Placeholder for releasing the qubit.
Conceptually, freeing a qubit would return its virtual ID to the runtime's pool so the underlying physical qubit can be used to store another state. In the current SDK implementation this method is a no-op stub — calling it has no effect, and VirtID reuse is handled implicitly by the runtime after a measurement.