Quantum types¶
euqalyptus.types.quantum exposes three qubit-flavored classes plus a small factory function. All inherit from Qubit (which is the shared base that defines the gate methods).
Source: euqalyptus/types/quantum/qubit.py.
LocalQubit¶
Represents a qubit allocated locally in the current node. Constructing a LocalQubit() inside a Qoala program records the equivalent of qnet.new_qubit.
from euqalyptus.types.quantum import LocalQubit
q = LocalQubit()
q.X() # records qnet.x %q
q.H() # records qnet.hadamard
m = q.measure() # records qnet.measure, returns a Bit AST
See Qubit operations for the full method list.
EntangledQubit¶
Represents a qubit that has been entangled with a remote node. You typically don't instantiate this directly — use the Entangle() factory below.
EntangledQubit carries the same gate methods as LocalQubit. The lowering treats them slightly differently: an EntangledQubit corresponds to a qnet.eprs-produced value rather than a qnet.new_qubit result.
Entangle("Name", n=1) — the factory¶
from euqalyptus.types.quantum import Entangle
from euqalyptus.operations import Remote
Remote("Bob")
q = Entangle("Bob") # one entangled qubit shared with Bob
qs = Entangle("Bob", n=3) # tuple of three entangled qubits
Entangle raises UnknownRemoteError if the named remote has not been declared with Remote(...) first.
When n == 1, returns a single EntangledQubit. When n > 1, returns a tuple of EntangledQubits. Only the first element triggers the remote declaration in the AST.
ScopedQubit¶
ScopedQubit is a thin wrapper used in branching constructs to express that a qubit is being conditionally manipulated and "yielded" back out of the conditional region. It accepts a Qubit, an EntangledQubit, or a tuple of EntangledQubits.
from euqalyptus.types.quantum import ScopedQubit
cond_q = ScopedQubit(qubit)
You typically reach for ScopedQubit only inside branching blocks. You can check branching for more information about these statements.
Where qnet.qubit comes from¶
In the emitted HIR, every qubit-typed value is !qnet.qubit. The mapping:
| SDK class | Recorded HIR op |
|---|---|
LocalQubit() |
%q = qnet.new_qubit : !qnet.qubit |
Entangle("Bob") |
%q = qnet.eprs { remote = @Bob } : !qnet.qubit |
Entangle("Bob", n=3) |
three qnet.eprs ops sharing the same remote |
After the HIR→MIR lowering in qoala-mlir, each !qnet.qubit value is rewritten to an i32 qubit pointer. From the user's perspective, that's invisible.
API reference¶
qubit ¶
LocalQubit ¶
LocalQubit()
Bases: Qubit
A locally-allocated qubit.
Constructing LocalQubit() inside a @QoalaProgram body
records a qnet.new_qubit op, allocating and initializing a
fresh local qubit on the current node. The returned value is a
full :class:Qubit — all the gate, rotation, and measurement
methods inherited from the base class are available on it.
Returns:
| Name | Type | Description |
|---|---|---|
A |
class: |
EntangledQubit ¶
EntangledQubit(name: str)
Bases: Qubit
The local half of an EPR pair shared with a remote node.
Constructing EntangledQubit("Alice") inside a @QoalaProgram
body records a qnet.eprs { remote = @Alice } op, requesting an
entangled pair with the named remote. The returned value is the
local half of that pair, exposed as a regular :class:Qubit.
Most users should prefer the :func:Entangle factory, which also
handles the n > 1 case of requesting several pairs in one go.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The symbolic name of the remote peer with which to
entangle. The remote must have been declared via
:class: |
required |
ScopedQubit ¶
ScopedQubit(qubit: Qubit | EntangledQubit | Tuple[EntangledQubit, ...])
Bases: Qubit
A recording-time proxy for a qubit that must survive a branching region.
ScopedQubit is used inside with if_cond(...) blocks to
wrap a qubit whose post-branch identity must be the
scf.if-yielded SSA result rather than an in-region SSA value.
Calling ScopedQubit(q) captures q and exposes the same
qubit-method surface (X, Y, measure, …) on the
wrapper; while the branch is open, calls on the wrapper are
routed to the captured original, and the chain of operations
applied through the wrapper is tracked so the front-end can emit
a well-formed scf.yield. After the branch exits, the wrapper
rebinds to the SCF result and subsequent operations are recorded
on that.
See the implementation section of the accompanying paper for the
full rationale; the test fixtures in
tests/bindings/test_branching.py exercise the mechanism.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
Qubit | EntangledQubit | Tuple[EntangledQubit, ...]
|
The qubit value to capture. Must already be a
:class: |
required |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If called without a qubit argument. |
assign ¶
assign(value: Any)
Re-assign the captured value of this scoped qubit.
Used internally by the branching machinery to rebind a
:class:ScopedQubit after a branch arm has been recorded; not
typically called by user code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The new captured value. |
required |
Entangle ¶
Entangle(name: str, n: int = 1) -> EntangledQubit | Tuple[EntangledQubit, ...]
Generate n entangled qubits with a remote peer.
Records the appropriate number of qnet.eprs ops against the
named remote and returns the local halves. With n = 1 (the
default), the function returns a single :class:EntangledQubit;
with n > 1, it returns a tuple of them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The symbolic name of the remote peer. The remote must
have been declared via
:class: |
required |
n
|
int
|
The number of entangled pairs to request. Defaults to |
1
|
Returns:
| Type | Description |
|---|---|
EntangledQubit | Tuple[EntangledQubit, ...]
|
A single :class: |
EntangledQubit | Tuple[EntangledQubit, ...]
|
tuple of |
EntangledQubit | Tuple[EntangledQubit, ...]
|
representing the local half of one of the requested pairs. |
Raises:
| Type | Description |
|---|---|
UnknownRemoteError
|
If |