Skip to content

qnetbench.api

The portable API shim. This package and qnetbench.trace are the two frozen contracts of the suite — applications import from here and nowhere else, and a backend is free to implement the surface however it likes.

Narrative guide: Applications and Extending the suite.

qnetbench.api

qnetbench.api — the portable API shim.

This package and qnetbench.trace are the two frozen contracts of the suite. Applications import only from here.

Duration module-attribute

Duration: TypeAlias = float

NodeId module-attribute

NodeId: TypeAlias = str

Purpose module-attribute

Purpose = Literal['keep', 'measure']

Role module-attribute

Role: TypeAlias = str

SimTime module-attribute

SimTime: TypeAlias = float

ViolationKind module-attribute

ViolationKind = Literal[
    "fidelity", "deadline", "staleness", "dropped"
]

API_VERSION module-attribute

API_VERSION = '0.2.0'

Application

Bases: Protocol

A benchmark application.

roles() names the participants (e.g. ["alice", "bob"]); the harness maps each role onto a node and calls run once per role, concurrently.

name instance-attribute

name: str

roles

roles() -> list[Role]
Source code in qnetbench/api/application.py
def roles(self) -> list[Role]: ...

run

run(
    host: Host, role: Role, cfg: dict[str, object]
) -> AppOutcome
Source code in qnetbench/api/application.py
def run(self, host: Host, role: Role, cfg: dict[str, object]) -> AppOutcome: ...

ClassicalSocket

Bases: Protocol

send

send(msg: bytes) -> None
Source code in qnetbench/api/host.py
def send(self, msg: bytes) -> None: ...

recv

recv() -> bytes
Source code in qnetbench/api/host.py
def recv(self) -> bytes: ...

EntanglementHandle dataclass

EntanglementHandle(
    req_id: int,
    fidelity: float,
    latency: Duration,
    pair_age: Duration,
    qubit: Qubit | None = None,
    outcome: int | None = None,
    violations: list[ViolationKind] = list(),
)

The result of one delivered entangled pair, from the local host's side.

For purpose="keep", qubit is the live local half. For purpose="measure", the backend measured on delivery and outcome holds the bit (qubit is None). violations is non-empty when the delivery broke its Demand contract; the handle is still returned so applications can decide how to degrade.

req_id instance-attribute

req_id: int

fidelity instance-attribute

fidelity: float

latency instance-attribute

latency: Duration

pair_age instance-attribute

pair_age: Duration

qubit class-attribute instance-attribute

qubit: Qubit | None = None

outcome class-attribute instance-attribute

outcome: int | None = None

violations class-attribute instance-attribute

violations: list[ViolationKind] = field(
    default_factory=list
)

ok property

ok: bool

EPRSocket

Bases: Protocol

Requests entanglement with one peer, under a demand contract.

request

request(n: int, demand: Demand) -> list[EntanglementHandle]
Source code in qnetbench/api/host.py
def request(self, n: int, demand: Demand) -> list[EntanglementHandle]: ...

Host

Bases: Protocol

Everything an application role can do. Bound to one node for one run.

node property

node: NodeId

rng property

rng: Generator

epr_socket

epr_socket(peer: NodeId) -> EPRSocket
Source code in qnetbench/api/host.py
def epr_socket(self, peer: NodeId) -> EPRSocket: ...

classical_socket

classical_socket(peer: NodeId) -> ClassicalSocket
Source code in qnetbench/api/host.py
def classical_socket(self, peer: NodeId) -> ClassicalSocket: ...

qalloc

qalloc() -> Qubit
Source code in qnetbench/api/host.py
def qalloc(self) -> Qubit: ...

qsend

qsend(peer: NodeId, qubit: Qubit) -> None
Source code in qnetbench/api/host.py
def qsend(self, peer: NodeId, qubit: Qubit) -> None: ...

qrecv

qrecv(peer: NodeId) -> Qubit
Source code in qnetbench/api/host.py
def qrecv(self, peer: NodeId) -> Qubit: ...

now

now() -> SimTime
Source code in qnetbench/api/host.py
def now(self) -> SimTime: ...

sleep

sleep(duration: Duration) -> None
Source code in qnetbench/api/host.py
def sleep(self, duration: Duration) -> None: ...

record_measurement

record_measurement(basis: Basis, result: int) -> None
Source code in qnetbench/api/host.py
def record_measurement(self, basis: Basis, result: int) -> None: ...

Qubit

Bases: Protocol

A local qubit handle. Physics lives in the backend; the app only sees ops.

apply

apply(gate: Gate, *params: float) -> None
Source code in qnetbench/api/host.py
def apply(self, gate: Gate, *params: float) -> None: ...

cnot

cnot(target: Qubit) -> None
Source code in qnetbench/api/host.py
def cnot(self, target: Qubit) -> None: ...

cz

cz(target: Qubit) -> None
Source code in qnetbench/api/host.py
def cz(self, target: Qubit) -> None: ...

measure

measure(basis: Basis = Z) -> int
Source code in qnetbench/api/host.py
def measure(self, basis: Basis = Basis.Z) -> int: ...

free

free() -> None
Source code in qnetbench/api/host.py
def free(self) -> None: ...

AppOutcome

Bases: BaseModel

What an application role reports when it finishes.

utility is application-defined in [0, 1] and is the quantity the staleness/fidelity curves are plotted against.

role instance-attribute

role: Role

success instance-attribute

success: bool

utility class-attribute instance-attribute

utility: float = Field(ge=0.0, le=1.0)

payload class-attribute instance-attribute

payload: dict[str, object] = Field(default_factory=dict)

Basis

Bases: str, Enum

Measurement basis for a local qubit. Arbitrary-angle measurements are expressed by rotating the qubit (RY/RZ) and then measuring in Z.

Z class-attribute instance-attribute

Z = 'Z'

X class-attribute instance-attribute

X = 'X'

Y class-attribute instance-attribute

Y = 'Y'

Demand

Bases: BaseModel

The contract attached to a request for entanglement.

This is what makes the suite discriminative: schedulers read it, the trace records requested-vs-delivered against it, and the characterizer mines its distribution across an application's run.

model_config class-attribute instance-attribute

model_config = {'frozen': True}

min_fidelity class-attribute instance-attribute

min_fidelity: float = Field(0.0, ge=0.0, le=1.0)

latency_budget class-attribute instance-attribute

latency_budget: Duration | None = None

deadline class-attribute instance-attribute

deadline: SimTime | None = None

staleness_tolerance class-attribute instance-attribute

staleness_tolerance: Duration | None = None

priority class-attribute instance-attribute

priority: float = 1.0

purpose class-attribute instance-attribute

purpose: Purpose = 'keep'

Gate

Bases: str, Enum

Single-qubit gates. Two-qubit gates are methods on Qubit (cnot/cz).

I class-attribute instance-attribute

I = 'I'

X class-attribute instance-attribute

X = 'X'

Y class-attribute instance-attribute

Y = 'Y'

Z class-attribute instance-attribute

Z = 'Z'

H class-attribute instance-attribute

H = 'H'

S class-attribute instance-attribute

S = 'S'

T class-attribute instance-attribute

T = 'T'

RX class-attribute instance-attribute

RX = 'RX'

RY class-attribute instance-attribute

RY = 'RY'

RZ class-attribute instance-attribute

RZ = 'RZ'

Value types

qnetbench.api.types

Core value types for the portable API shim.

This module has no dependencies inside qnetbench, so both qnetbench.api and qnetbench.trace can build on it without a cycle.

NodeId module-attribute

NodeId: TypeAlias = str

Role module-attribute

Role: TypeAlias = str

SimTime module-attribute

SimTime: TypeAlias = float

Duration module-attribute

Duration: TypeAlias = float

Purpose module-attribute

Purpose = Literal['keep', 'measure']

ViolationKind module-attribute

ViolationKind = Literal[
    "fidelity", "deadline", "staleness", "dropped"
]

Basis

Bases: str, Enum

Measurement basis for a local qubit. Arbitrary-angle measurements are expressed by rotating the qubit (RY/RZ) and then measuring in Z.

Z class-attribute instance-attribute
Z = 'Z'
X class-attribute instance-attribute
X = 'X'
Y class-attribute instance-attribute
Y = 'Y'

Gate

Bases: str, Enum

Single-qubit gates. Two-qubit gates are methods on Qubit (cnot/cz).

I class-attribute instance-attribute
I = 'I'
X class-attribute instance-attribute
X = 'X'
Y class-attribute instance-attribute
Y = 'Y'
Z class-attribute instance-attribute
Z = 'Z'
H class-attribute instance-attribute
H = 'H'
S class-attribute instance-attribute
S = 'S'
T class-attribute instance-attribute
T = 'T'
RX class-attribute instance-attribute
RX = 'RX'
RY class-attribute instance-attribute
RY = 'RY'
RZ class-attribute instance-attribute
RZ = 'RZ'

Demand

Bases: BaseModel

The contract attached to a request for entanglement.

This is what makes the suite discriminative: schedulers read it, the trace records requested-vs-delivered against it, and the characterizer mines its distribution across an application's run.

model_config class-attribute instance-attribute
model_config = {'frozen': True}
min_fidelity class-attribute instance-attribute
min_fidelity: float = Field(0.0, ge=0.0, le=1.0)
latency_budget class-attribute instance-attribute
latency_budget: Duration | None = None
deadline class-attribute instance-attribute
deadline: SimTime | None = None
staleness_tolerance class-attribute instance-attribute
staleness_tolerance: Duration | None = None
priority class-attribute instance-attribute
priority: float = 1.0
purpose class-attribute instance-attribute
purpose: Purpose = 'keep'

AppOutcome

Bases: BaseModel

What an application role reports when it finishes.

utility is application-defined in [0, 1] and is the quantity the staleness/fidelity curves are plotted against.

role instance-attribute
role: Role
success instance-attribute
success: bool
utility class-attribute instance-attribute
utility: float = Field(ge=0.0, le=1.0)
payload class-attribute instance-attribute
payload: dict[str, object] = Field(default_factory=dict)

The runtime surface

qnetbench.api.host

The runtime surface an application sees. Applications program against these Protocols and never import a backend or a simulator.

Qubit

Bases: Protocol

A local qubit handle. Physics lives in the backend; the app only sees ops.

apply
apply(gate: Gate, *params: float) -> None
Source code in qnetbench/api/host.py
def apply(self, gate: Gate, *params: float) -> None: ...
cnot
cnot(target: Qubit) -> None
Source code in qnetbench/api/host.py
def cnot(self, target: Qubit) -> None: ...
cz
cz(target: Qubit) -> None
Source code in qnetbench/api/host.py
def cz(self, target: Qubit) -> None: ...
measure
measure(basis: Basis = Z) -> int
Source code in qnetbench/api/host.py
def measure(self, basis: Basis = Basis.Z) -> int: ...
free
free() -> None
Source code in qnetbench/api/host.py
def free(self) -> None: ...

EntanglementHandle dataclass

EntanglementHandle(
    req_id: int,
    fidelity: float,
    latency: Duration,
    pair_age: Duration,
    qubit: Qubit | None = None,
    outcome: int | None = None,
    violations: list[ViolationKind] = list(),
)

The result of one delivered entangled pair, from the local host's side.

For purpose="keep", qubit is the live local half. For purpose="measure", the backend measured on delivery and outcome holds the bit (qubit is None). violations is non-empty when the delivery broke its Demand contract; the handle is still returned so applications can decide how to degrade.

req_id instance-attribute
req_id: int
fidelity instance-attribute
fidelity: float
latency instance-attribute
latency: Duration
pair_age instance-attribute
pair_age: Duration
qubit class-attribute instance-attribute
qubit: Qubit | None = None
outcome class-attribute instance-attribute
outcome: int | None = None
violations class-attribute instance-attribute
violations: list[ViolationKind] = field(
    default_factory=list
)
ok property
ok: bool

EPRSocket

Bases: Protocol

Requests entanglement with one peer, under a demand contract.

request
request(n: int, demand: Demand) -> list[EntanglementHandle]
Source code in qnetbench/api/host.py
def request(self, n: int, demand: Demand) -> list[EntanglementHandle]: ...

ClassicalSocket

Bases: Protocol

send
send(msg: bytes) -> None
Source code in qnetbench/api/host.py
def send(self, msg: bytes) -> None: ...
recv
recv() -> bytes
Source code in qnetbench/api/host.py
def recv(self) -> bytes: ...

Host

Bases: Protocol

Everything an application role can do. Bound to one node for one run.

node property
node: NodeId
rng property
rng: Generator
epr_socket
epr_socket(peer: NodeId) -> EPRSocket
Source code in qnetbench/api/host.py
def epr_socket(self, peer: NodeId) -> EPRSocket: ...
classical_socket
classical_socket(peer: NodeId) -> ClassicalSocket
Source code in qnetbench/api/host.py
def classical_socket(self, peer: NodeId) -> ClassicalSocket: ...
qalloc
qalloc() -> Qubit
Source code in qnetbench/api/host.py
def qalloc(self) -> Qubit: ...
qsend
qsend(peer: NodeId, qubit: Qubit) -> None
Source code in qnetbench/api/host.py
def qsend(self, peer: NodeId, qubit: Qubit) -> None: ...
qrecv
qrecv(peer: NodeId) -> Qubit
Source code in qnetbench/api/host.py
def qrecv(self, peer: NodeId) -> Qubit: ...
now
now() -> SimTime
Source code in qnetbench/api/host.py
def now(self) -> SimTime: ...
sleep
sleep(duration: Duration) -> None
Source code in qnetbench/api/host.py
def sleep(self, duration: Duration) -> None: ...
record_measurement
record_measurement(basis: Basis, result: int) -> None
Source code in qnetbench/api/host.py
def record_measurement(self, basis: Basis, result: int) -> None: ...

The application contract

qnetbench.api.application

The application contract. An application is written once here and runs on any backend, under any arbitration mode.

Application

Bases: Protocol

A benchmark application.

roles() names the participants (e.g. ["alice", "bob"]); the harness maps each role onto a node and calls run once per role, concurrently.

name instance-attribute
name: str
roles
roles() -> list[Role]
Source code in qnetbench/api/application.py
def roles(self) -> list[Role]: ...
run
run(
    host: Host, role: Role, cfg: dict[str, object]
) -> AppOutcome
Source code in qnetbench/api/application.py
def run(self, host: Host, role: Role, cfg: dict[str, object]) -> AppOutcome: ...