Skip to content

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 on q.
  • For operations that take a target (q.cnot(target)), the recorded op produces fresh qubit values for both — your q and target Python 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:Bit-typed SSA value carrying the measurement

QoalaIntegerType

outcome (0 or 1).

X

X()

Record an X (Pauli-X) gate on this qubit.

Y

Y()

Record a Y (Pauli-Y) gate on this qubit.

Z

Z()

Record a Z (Pauli-Z) gate on this qubit.

H

H()

Record a Hadamard gate on this qubit.

S

S()

Record an S gate (Z-rotation of angle π/2) on this qubit.

T

T()

Record a T gate (Z-rotation of angle π/4) on this qubit.

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. May be a Python int or a Qoala integer-typed value.

0
d int | QoalaIntegerType

Denominator-exponent of the discrete angle specification. Defaults to 0. May be a Python int or a Qoala integer-typed value.

0
angle float | QoalaFloatingPointType | None

Optional explicit floating-point angle, in radians. Defaults to None. When provided, takes precedence over n and d.

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 cnot between two qubits from different remotes is not meaningful in this SDK).

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.