Qoala backend¶
netqmpi -n <N> app.py --qoala [--shots N] [--config qoala.yaml]
Qoala models the software/hardware architecture of a quantum-internet node: task scheduling, multitasking between programs, and a configurable qdevice, all on top of NetSquid. Where NetQASM simulates the network, Qoala simulates what happens inside a node while the network runs.
Simulation only
Qoala is a NetSquid-based simulator. This backend has no real-hardware execution path and must not be considered on par with a physical deployment.
Packages:
qoala,netsquid,netqasm2.xPython: 3.10 – 3.12
Adapter:
netqmpi.runtime.adapters.qoala
Installation¶
Qoala needs its own environment, because its netqasm 2.x is incompatible
with the 1.x used by the NetQASM backend:
conda create -n qoala python=3.11 -y
conda activate qoala
pip install netsquid --extra-index-url https://<user>:<pwd>@pypi.netsquid.org
pip install qoala --extra-index-url https://<user>:<pwd>@pypi.netsquid.org
pip install netqmpi
What it supports¶
Primitive |
Status |
|---|---|
|
✅ full teleportation (EPR + BSM + corrections) |
|
❌ |
|
❌ |
|
❌ |
|
❌ |
Classically controlled gates |
❌ |
Several circuits per rank |
❌ exactly one circuit per rank |
Gates: H X Y Z directly; S SDG T TDG as fixed rot_z rotations;
RX RY RZ discretised to multiples of π/16; SWAP as three CNOTs; and
controlled X (cnot) and Z (cphase).
What was fixed
The controlled-gate table was written against names the SDK never emits, and three things followed from that:
cxandczwere unreachable. The table compared the target gate’s name against"RX"and"RZ", but the SDK records a CNOT as a controlledGate('X')and a CZ as a controlledGate('Z'). Both of the gates the table meant to support raisedNotImplementedError.crz(theta)came out as a plain CZ. Acrzdoes record a controlledGate('RZ'), so it fell into the"RZ"branch and was emitted ascphase— a controlled-Z — with the angle silently discarded. It is now refused explaining why: NetQASM has no controlled-rotation instruction.SWAPreached no table at all. The SDK records it as a two-qubitGate, so it was dispatched down the single-qubit path and died as an unknown name.
Caution
A local gate placed on both sides of a round trip — swap a qubit into a
scratch slot, send it away, receive it back, swap it out again — makes the
generated .iqoala program stop before returning its measurement, and
_build_counts then raises KeyError looking for a host variable that never
came back. The round trip alone is fine, and so are the swaps alone. This is
what stops apps/ghz.py running on Qoala; it is pinned as a strict xfail in
test/test_qoala_backend.py so that it reports the day it is fixed.
More than one circuit per rank is rejected explicitly:
NotImplementedError: The Qoala backend currently supports exactly one circuit
per rank (rank 0 created 2).
Configuration¶
This is the backend with the richest noise model — it is the reason to choose it.
# qoala.yaml
shots: 1000
seed: 7
qoala:
link_fidelity: 0.8 # EPR-pair fidelity in [0.25, 1.0]
link_duration: 1000.0 # EPR generation time (ns)
qnos_instr_time: 1000.0 # one quantum-processor instruction (ns)
hardware: # qdevice noise model; omit for a perfect device
t1: 0
t2: 0
single_qubit_gate_time: 5e3
two_qubit_gate_time: 200e3
single_qubit_gate_depolar_prob: 0.1
two_qubit_gate_depolar_prob: 0.0
link_fidelity below 1.0 uses a depolarising link with
prob_max_mixed = (4/3)(1 - link_fidelity); a value outside [0.25, 1.0] is
rejected when the config is built. t1 == t2 == 0 means “no memory noise”, so
the defaults describe a perfect qdevice.
The full field list is in the qoala block.
Note
Depolarising noise applies to the gates only. INSTR_INIT and
INSTR_MEASURE carry their own duration but no depolarising error, so there is
no separate readout-flip model.
Execution model¶
The adapter compiles each rank’s circuit to .iqoala program text rather
than driving an API. Local gates and measurements are buffered and flushed into
QL blocks; a qsend or qrecv closes the current block and emits the
teleportation blocks around it.
All ranks run in the same process, and the joint NetSquid simulation is deferred
until every rank has left its with comm: block. Each rank compiles and
registers its program on __exit__; when the last rank registers, the executor
builds the Qoala network and runs one simulation for all ranks at once.
The communicator module imports no qoala package: program text is produced
by QoalaCircuitAdapter and the simulation is driven by QoalaExecutorAdapter,
which imports qoala and netsquid lazily inside its own methods.
Results¶
comm.results is a {bitstring: count} histogram for this rank alone,
ordered by ascending classical-bit index. A rank that returns no measurements
gets an empty dict.
Validation experiments¶
The repository ships three experiments validating this backend, under
scripts/experiments/:
- Hardware-parameter propagation
Checks that qdevice noise (T1/T2, gate times, depolarisation) is propagated faithfully through NetQMPI’s translation, by comparing against a hand-written native Qoala control program with the same qdevice and a perfect link.
- EPR fidelity sweep
With a perfect qdevice, sweeps the EPR-pair fidelity of
qsend/qrecvand compares against the perfect link.- Scheduling / multitasking
Two NetQMPI programs sharing a node. Qoala’s scheduler reduces the makespan by 18.9% without degrading fidelity, with a CPS/QPS Gantt chart of the interleaving.
The fidelity probe used throughout is a distributed superposition teleported and
read out in the X basis: measuring |+⟩ directly in Z gives 50/50 even
without noise, so it is useless as a fidelity measure. Measuring in the state’s
own basis makes fidelity run from 1.0 (noiseless) to 0.5 (fully depolarised),
sensitive to T1, T2 and depolarisation.